随着规模的增加, 将机器部署到多个地区的多个机房是必然的选择.

region/zone/cluster

region 是地区, 比如上海和北京, 两个地区的网络延迟相对较高, 稳定性相对较差.

zone 一般指代机房, 比如上海的机房 A 和机房 B. 同地区的多个机房之间网络环境相对可靠, 有些情况下, 可以将同地区的多个机房等同看待.

cluster 指 k8s 集群. 一般而言, 我们允许一个集群分布在同地区的多个机房之间, 但不允许涉及多个地区. 主要是因为地区之间的网络相对较差, 同时也会使得 cluster 变成单点.

所以在多地区多机房的情况下, 我们大多数时候会选择每个地区一个 k8s 集群的多集群方案.

调用拓扑

在这种多集群下, 我们希望提供简单的, 动态的调用拓扑.

  • 调用拓扑对业务基本透明, 开发并不需要关注请求是被分发到哪个地区和集群.
  • 支持手动&自动调整调用拓扑, 允许根据集群间的资源调整资源比例, 支持手动&自动降级.

具体而言, 我们假设集群 X 中的应用 A 调用应用 B.

集群内调用是最普遍的情况: 应用 B 也部署在集群 X 中, 即 A/B 部署在同一个集群.

跨集群的调用情况比较复杂, 可能包括:

  • 应用 B 仅部署在集群 Y 中.
  • 应用 B 同时部署在集群 X 和集群 Y
    • 且我们允许 A(X) 对 B 的调用按一定比例分布在集群 X 和集群 Y. 这种调用拓扑违背了就近原则, 非常少见.
    • 且集群 X 中的应用 B 无法正常提供服务, 经过手动/自动降级后, 调用被分发到集训 Y.

随着时代的发展, 上述及一些更高级的功能都可以通过现成的开源方案实现. 以 Istio 为例, 其:

  • 首先通过在每个集群安装控制面板并且相互共享信息, 实现 Mesh 网络内的集群相互感知
  • 其次通过在集群边缘安装 Engress/Ingress Gateway 处理跨集群的流量, 主要功能为代理转发和加解密.
  • 最后在向 Envoy 下发规则时, 考虑多个集群.

持久化应用

大多数时候, 业务应用是无状态的, 并不需要感知部署拓扑. 但类似 MySQL/Redis 这种有状态的应用, 需要感知部署拓扑. 我们可以将其划分成三种情况:

  • Global, 应用仅部署在某个集群. 其他集群访问该应用的流量都应该跨集群分发. 我们需要注意应用对延迟的容忍度和对网络带宽的使用情况, 尽量避免这种应用的出现.
  • Local, 应用在每个集群都部署, 不同集群之间的实例相互不影响. 用于缓存数据的 Redis 是典型场景, 其流量大, 延迟低, 很难接受跨地区的网络. 但需要注意, 多个集群间的实例并不交互数据, 即使仅用于缓存, 也需要在设计时考虑这点.
  • Master/Slave, 应用在多个集群, 但仅有一个集群的实例做为 Master 支持写操作, 其他集群的实例通过主从复制同步数据后, 仅支持读操作. 集群内的读操作可以直接分发到本集群的 Slave 节点, 写操作分发到跨集群的 Master 节点.