一个协调服务,理想状态下大概需要满足以下五个目标:

  1. 可用性角度:高可用。协调服务作为集群的控制面存储,它保存了各个服务的部署、运行信息。若它故障,可能会导致集群无法变更、服务副本数无法协调。业务服务若此时出现故障,无法创建新的副本,可能会影响用户数据面。
  2. 数据一致性角度:提供读取“最新”数据的机制。既然协调服务必须具备高可用的目标,就必然不能存在单点故障(single point of failure),而多节点又引入了新的问题,即多个节点之间的数据一致性如何保障?比如一个集群 3 个节点 A、B、C,从节点 A、B 获取服务镜像版本是新的,但节点 C 因为磁盘 I/O 异常导致数据更新缓慢,若控制端通过 C 节点获取数据,那么可能会导致读取到过期数据,服务镜像无法及时更新。
  3. 容量角度:低容量、仅存储关键元数据配置。协调服务保存的仅仅是服务、节点的配置信息(属于控制面配置),而不是与用户相关的数据。所以存储上不需要考虑数据分片,无需过度设计。
  4. 功能:增删改查,监听数据变化的机制。协调服务保存了服务的状态信息,若服务有变更或异常,相比控制端定时去轮询检查一个个服务状态,若能快速推送变更事件给控制端,则可提升服务可用性、减少协调服务不必要的性能开销。
  5. 运维复杂度:可维护性。在分布式系统中往往会遇到硬件 Bug、软件 Bug、人为操作错误导致节点宕机,以及新增、替换节点等运维场景,都需要对协调服务成员进行变更。若能提供 API 实现平滑地变更成员节点信息,就可以大大降低运维复杂度,减少运维成本,同时可避免因人工变更不规范可能导致的服务异常。

当时其实是有 ZooKeeper 的,但是他们为什么不用 ZooKeeper 呢?

  • ZooKeeper 不支持通过 API 安全地变更成员,需要人工修改一个个节点的配置,并重启进程。
  • ZooKeeper 是用 Java 编写的,部署较繁琐,占用较多的内存资源,同时 RPC API 是 Thrift,在 ZooKeeper 之外很少使用。无法使用 curl 之类的常用工具与之互动,CoreOS 期望使用比较简单的 HTTP + JSON。

etcd v1 和 v2 诞生

为了解决数据一致性问题,需要引入一个共识算法,确保各节点数据一致性,并可容忍一定节点故障。常见的共识算法有 Paxos、ZAB、Raft 等。CoreOS 团队选择了易理解实现的 Raft 算法,它将复杂的一致性问题分解成 Leader 选举、日志同步、安全性三个相对独立的子问题,只要集群一半以上节点存活就可提供服务,具备良好的可用性。

key-value 存储引擎上,ZooKeeper 使用的是 Concurrent HashMap,而 etcd 使用的是则是简单内存树,它的节点数据结构精简后如下,含节点路径、值、孩子节点信息。这是一个典型的低容量设计,数据全放在内存,无需考虑数据分片,只能保存 key 的最新版本,简单易实现。

image.png

  1. type node struct {
  2. Path string //节点路径
  3. Parent *node //关联父亲节点
  4. Value string //key的value值
  5. ExpireTime time.Time //过期时间
  6. Children map[string]*node //此节点的孩子节点
  7. }

最后我们再来看可维护性。Raft 算法提供了成员变更算法,可基于此实现成员在线、安全变更,同时此协调服务使用 Go 语言编写,无依赖,部署简单。

image.png

那么 etcd 这个名字是怎么来的呢?其实它源于两个方面,unix 的“/etc”文件夹和分布式系统 (“D”istribute system) 的 D,组合在一起表示 etcd 是用于存储分布式配置的信息存储服务。

image.png

为什么 Kubernetes 使用 etcd?

以 Google、RedHat 为首的阵营,基于 Google 多年的大规模容器管理系统 Borg 经验,结合社区的建议和实践,构建以 Kubernetes 为核心的容器生态圈。相比 Docker 的垄断、独裁,Kubernetes 社区推行的是民主、开放原则,Kubernetes 每一层都可以通过插件化扩展,在 Google、RedHat 的带领下不断发展壮大,etcd 也进入了快速发展期。

下图我从构建分布式系统的核心要素角度,给你总结了 etcd v2 核心技术点。无论是 NoSQL 存储还是 SQL 存储、文档存储,其实大家要解决的问题都是类似的,基本就是图中总结的数据模型、复制、共识算法、API、事务、一致性、成员故障检测等方面。

image.png

etcd v3 诞生

Kubernetes 社区呼吁支持新的存储、批评 etcd 不可靠的声音开始不断出现。具体有哪些问题呢?我给你总结了如下图:

image.png

  1. 功能局限性问题
    1. etcd v2 不支持范围查询和分页
    2. etcd v2 不支持多 key 事务
  2. Watch 机制可靠性问题
    1. 不支持保存 key 历史版本的数据库
  3. 性能瓶颈问题
    1. etcd v2 早期使用了简单、易调试的 HTTP/1.x API,但是随着 Kubernetes 支撑的集群规模越来越大,HTTP/1.x 协议的瓶颈逐渐暴露出来
  4. 内存开销问题

为什么 etcd v2 有以上若干问题,Consul 等其他竞品依然没有被 Kubernetes 支持呢?

  • 一方面当时包括 Consul 在内,没有一个开源项目是十全十美完全满足 Kubernetes 需求。而 CoreOS 团队一直在聆听社区的声音并积极改进,解决社区的痛点。用户吐槽 etcd 不稳定,他们就设计实现自动化的测试方案,模拟、注入各类故障场景,及时发现修复 Bug,以提升 etcd 稳定性。
  • 另一方面,用户吐槽性能问题,针对 etcd v2 各种先天性缺陷问题,他们从 2015 年就开始设计、实现新一代 etcd v3 方案去解决以上痛点,并积极参与 Kubernetes 项目,负责 etcd v2 到 v3 的存储引擎切换,推动 Kubernetes 项目的前进。同时,设计开发通用压测工具、输出 Consul、ZooKeeper、etcd 性能测试报告,证明 etcd 的优越性。

下面的时间轴图,我给你总结了 etcd3 重要特性及版本发布时间。从图中你可以看出,从 3.0 到未来的 3.5,更稳、更快是 etcd 的追求目标。

image.png

v3 方案的发布,也标志着 etcd 进入了技术成熟期,成为云原生时代的首选元数据存储产品。