Follow me on GitHub

为什么单机应用有时也“应该”拆分为多个容器?

分布式系统容器化为多个容器容易理解,但为什么单机应用有时也需要拆分为多个容器呢,直接放到一个容器中不行吗?

首先,明确下应用容器化目的:

  1. 资源隔离(CPU & 内存)
  2. 管理隔离(不同镜像由不同团队负责)
  3. 关注点分离(每个容器仅做一件事,并将其做好)

因此,如果单机应用有以上需求,就需要考虑将其拆分为多个容器。

当然,单机应用拆分为多个容器后,并非就变成分布式系统了,因为拆分后的容器通常借助 Kubernetes 的 Pod 运行在 同一物理节点 上,因此依然可视之为单机应用,只不过该应用现在由多个进程(容器)组成。

Pod 即 host,类似物理主机、虚拟机,可以包含多个容器。

资源隔离

考虑一个单机应用,其功能为:接受文件上传,并解析文件内容。其中文件上传属于用户界面的功能,实时性要求高,而文件解析属于后台任务,耗时久、实时性要求低。

容器化之前,如果有多个用户上传文件,则后台解析将占满 CPU 资源,从而导致用户上传界面反应迟钝,影响用户体验。

容器化后,如果只是把原本的应用跑在容器中,则原来的问题依然存在,因此需要把该应用拆分为两个容器,一个负责文件上传,一个负责文件解析,并为每个容器设置可用的资源(CPU、内存)额度,而且通过设置资源分配策略,可以做到:

  • 上传压力较少时,解析容器可以使用节点的所有CPU、内存;
  • 节点资源不足时,先杀死解析容器,以让出资源供上传容器使用;

可以看到,资源管理并非只是简单的“隔离”,还可以设计复杂的资源分配逻辑。

管理隔离

Amazon CEO 贝索斯的“披萨原则”形象地解释了合理的团队大小,即大家可以一起分吃一个披萨,如果单机应用所需团队的规模过大,则可将其拆分为多个容器,每个团队负责开发、交付一个容器镜像,从而减小团队规模。

有人会说,这种应用应该使用微服务架构进行拆分啊!

的确如此,拆分后的每个微服务对应一个容器,但部分微服务必须部署在 同一物理节点 上,比如前面的文件上传、解析的例子,拆分为微服务后,它们最好也部署在同一节点,以共享待处理的文件,避免网络传输带来的性能损耗,此时可以认为同一节点上的微服务共同组成一个单机应用。

关注点分离

即使你的单机应用不需要资源隔离,也不需要管理隔离,但你一定需要关注点分离。

通过分离关注点,每个容器仅仅负责一个相对简单的功能,可以独立开发、测试、部署、更新,整个系统也更容易理解。

例如,一个 Github 同步服务,明显应该拆分为独立容器,该同步容器作为 可复用 的容器模块,可以有效避免重复开发。

再例如,Service Mesh 中的 sidecar-proxy,是分离关注点的最佳示例,它可以用于 任何 应用,可复用性做到了极致。