etcd 是一个应用在分布式环境下的 key/value 存储服务。利用 etcd 的特性,应用程序可以在集群中共享信息、配置或作服务发现,etcd 会在集群的各个节点中复制这些数据并保证这些数据始终正确。etcd 无论是在 CoreOS 还是 Kubernetes 体系中都是不可或缺的一环。笔者由于项目的原因对 etcd 进行了一些了解,也已经使用了一段时间。同时在与同行的交流中常被问到 etcd 是什么、与 ZooKeeper 有什么不同。那么借着 etcd 0.5.0 即将发布的机会,向感兴趣的读者介绍一下 etcd,希望可以帮助读者了解 etcd 的工作原理以及具体实现,同时也作为 CoreOS 实战的第二部分内容为后面相关的部分进行铺垫。
随着 etcd 0.5.0 alpha (本文完稿时为 etcd 0.5.0 alpha.3)版发布,etcd 将在未来几周内迎来一次重要的更新。在 0.5.0 版里除了修复现有稳定版中的一系列 Bug 之外,一些新的特性和变更也将随之发布。这些变化将提升 etcd 服务安全性、可靠性和可维护性。
新的特性包括
规范词汇表;
新的 raft 算法实现;
新增 etcd node 身份标记;
WAL (Write-ahead logging) 增加 CRC 校验;
API 中新增 member {list, add, remove} 接口,原来的 list machines 接口将被移除,未来 etcd 集群中将不存在 machine 的称呼;
两个主要端口变更为 2379 (for client) 与 2380 (for peer/raft) 并成为 IANA 的注册端口。
重要的变更包括
运行时重构 (runtime reconfiguration)。用户不需要重启 etcd 服务即可实现对 etcd 集群结构进行变更。
摒弃通过配置文件配置 etcd 属性的方式,转而以 CLI (command-line interface) flags 或环境变量的方式实现 etcd 节点的配置。
每个节点可监听多个广播地址。监听的地址由原来的一个扩展到多个,用户可以根据需求实现更加复杂的集群环境,如搭建一个混合了私有云与公有云服务的 etcd 集群。
新增 proxy mode。
2. 规范词汇表etcd 0.5.0 版首次对 etcd 代码、文档及 CLI 中使用的术语进行了定义。
2.1. nodenode 指一个 raft 状态机实例。每个 node 都具有唯一的标识,并在处于 leader 状态时记录其它节点的步进数。
2.2. membermember 指一个 etcd 实例。member 运行在每个 node 上,并向这一 node 上的其它应用程序提供服务。
2.3. ClusterCluster 由多个 member 组成。每个 member 中的 node 遵循 raft 共识协议来复制日志。Cluster 接收来自 member 的提案消息,将其提交并存储于本地磁盘。
2.4. Peer同一 Cluster 中的其它 member。
2.5. ClientClient 指调用 Cluster API 的对象。
3. Raft 共识算法etcd 集群的工作原理基于 raft 共识算法 (The Raft Consensus Algorithm)。etcd 在 0.5.0 版本中重新实现了 raft 算法,而非像之前那样依赖于第三方库 go-raft 。raft 共识算法的优点在于可以在高效的解决分布式系统中各个节点日志内容一致性问题的同时,也使得集群具备一定的容错能力。即使集群中出现部分节点故障、网络故障等问题,仍可保证其余大多数节点正确的步进。甚至当更多的节点(一般来说超过集群节点总数的一半)出现故障而导致集群不可用时,依然可以保证节点中的数据不会出现错误的结果。
3.1. 集群建立与状态机raft 集群中的每个节点都可以根据集群运行的情况在三种状态间切换:follower, candidate 与 leader。leader 向 follower 同步日志,follower 只从 leader 处获取日志。在节点初始启动时,节点的 raft 状态机将处于 follower 状态并被设定一个 election timeout,如果在这一时间周期内没有收到来自 leader 的 heartbeat,节点将发起选举:节点在将自己的状态切换为 candidate 之后,向集群中其它 follower 节点发送请求,询问其是否选举自己成为 leader。当收到来自集群中过半数节点的接受投票后,节点即成为 leader,开始接收保存 client 的数据并向其它的 follower 节点同步日志。leader 节点依靠定时向 follower 发送 heartbeat 来保持其地位。任何时候如果其它 follower 在 election timeout 期间都没有收到来自 leader 的 heartbeat,同样会将自己的状态切换为 candidate 并发起选举。每成功选举一次,新 leader 的步进数都会比之前 leader 的步进数大1。
图 3-1 raft 状态切换示意图
3.2. 选举 3.2.1. 一个 candidate 成为 leader 需要具备三个要素:获得集群多数节点的同意;
集群中不存在比自己步进数更高的 candidate;
集群中不存在其他 leader。
3.2.2. 下面为一个 etcd 集群选举过程的简单描述:➢ 初始状态下集群中的所有节点都处于 follower 状态。
➢ 某一时刻,其中的一个 follower 由于没有收到 leader 的 heartbeat 率先发生 election timeout 进而发起选举。
➢ 只要集群中超过半数的节点接受投票,candidate 节点将成为即切换 leader 状态。
➢ 成为 leader 节点之后,leader 将定时向 follower 节点同步日志并发送 heartbeat。