2. etcd 基础回顾:Raft 协议原理、MVCC 机制、Watch 机制、Lease 租约机制
etcd 作为云原生的分布式键值存储,其核心设计围绕 强一致性、高可用 和 增量监听 展开。本节将深入回顾支撑 etcd 运行的四大基础机制:Raft 共识协议、MVCC 多版本并发控制、Watch 事件监听以及 Lease 租约机制。理解这些机制是后续进行压测沙盘资源变更与一致性复核的前提。
2.1 Raft 协议原理
Raft 是一种易于理解的分布式共识算法,用于在多个节点间复制日志,确保集群在部分节点故障时仍能对外提供一致的服务。etcd 使用 Raft 作为其一致性核心。
核心目标: 保证集群中所有非故障节点对同一个操作序列(日志条目)达成一致,从而维护状态机的一致性。
2.1.1 节点角色与任期
在任意时刻,每个 Raft 节点都处于以下三种角色之一:
- Leader(领导者): 负责处理所有客户端请求,并将操作日志复制到 Follower 节点。集群中只有一个 Leader。
- Follower(跟随者): 被动响应 Leader 和 Candidate 的请求。如果在一段时间内未收到 Leader 的心跳,会转变为 Candidate。
- Candidate(候选者): 用于选举新的 Leader。Candidate 会向其他节点发起投票请求。
Raft 将时间划分为任意长度的 任期(Term),每个任期以一次选举开始。任期号单调递增,作为逻辑时钟,用于检测过期信息。
2.1.2 领导者选举
当 Follower 在选举超时时间内未收到 Leader 的心跳,它会发起选举:
- 增加本地任期号,转换为 Candidate。
- 投票给自己,并向其他节点并行发送
RequestVote RPC。 - 如果获得超过半数(
n/2 + 1)节点的投票,则成为新的 Leader。 - 新 Leader 立即发送心跳(AppendEntries RPC)给所有节点,确立权威并阻止新的选举。
2.1.3 日志复制
这是 Raft 的核心流程,确保所有节点状态一致:
- 客户端请求 发送到 Leader。
- Leader 将操作追加到本地日志,状态为 未提交(Uncommitted)。
- Leader 并行向所有 Follower 发送
AppendEntries RPC,包含日志条目。 - Follower 收到后追加日志,并回复成功。
- Leader 收到超过半数的成功回复后,将日志条目标记为 已提交(Committed),并应用到状态机。
- Leader 在后续的心跳中通知 Follower 该条目已提交,Follower 随后应用到自己的状态机。
安全性保证: Raft 通过“选举限制”确保只有拥有最新日志的节点才能成为 Leader,通过“日志匹配特性”保证所有已提交的日志条目在集群中具有相同的顺序和内容。
2.2 MVCC 多版本并发控制机制
etcd 的 MVCC 机制通过保留键的历史版本,实现了无锁的并发读取和高效的事件回溯。每个键的每次修改都会生成一个新的版本号(revision),旧版本数据不会被立即覆盖。
2.2.1 核心数据结构
| 概念 | 说明 |
|---|---|
| Revision(全局版本号) | 一个单调递增的 64 位整数,每次事务(put/delete)都会递增。它是全局唯一的逻辑时钟。 |
| KeyValue 存储 | 底层使用 B+ 树(boltdb)存储。主键为 key_revision 的组合,支持按 revision 范围遍历。 |
| Buffer(内存缓冲区) | 最近写入的 key 会先缓存在内存中,加速读取。当 buffer 满或触发条件时,会 flush 到磁盘。 |
2.2.2 读写流程
- 写操作: 分配一个新的 revision,将
(key, value, revision)写入 buffer 和 boltdb。旧版本数据仍然保留在 boltdb 中。 - 读操作: 可以指定读取某个 revision 的快照数据,实现“读取历史版本”。如果不指定,则读取当前最新的已提交数据。
- 压缩(Compaction): 定期删除指定 revision 之前的旧版本数据,以回收存储空间。这是 etcd 运维的关键操作。
注意: 如果压缩不及时,历史版本会持续累积,导致存储空间膨胀和查询性能下降。在压测场景中,需要监控压缩进度和磁盘使用率。
2.3 Watch 机制
Watch 机制是 etcd 实现事件驱动架构的核心。客户端可以向 etcd 注册一个 Watcher,监听特定键或键前缀的变化。当被监听的键发生 put/delete 操作时,etcd 会实时推送事件给客户端。
2.3.1 工作流程
- 注册: 客户端发起
WatchgRPC 请求,指定要监听的 key 或前缀,以及起始 revision。 - 事件捕获: etcd 的 WatchableStore 模块监听 MVCC 的写操作。当有匹配的 key 被修改时,生成一个
Event(包含类型 PUT/DELETE 和键值对)。 - 推送: WatchableStore 将事件通过 gRPC stream 推送给所有注册了该 key 的客户端。
- 重连与恢复: 如果 Watch 连接断开,客户端可以使用上次收到的最后一个 revision 重新发起 Watch 请求,etcd 会从该 revision 开始重放事件,确保不丢失。
应用场景: 服务发现(监听某个目录下的服务实例变化)、配置同步(监听配置文件的变更)、分布式锁(监听锁释放事件)。
2.4 Lease 租约机制
Lease 是一种轻量级的分布式心跳保活机制。它允许一个 key 或一组 key 关联一个租约,租约具有一个 TTL(生存时间)。只要租约持有者定期续约,关联的 key 就保持有效;一旦租约过期,所有关联的 key 会被自动删除。
2.4.1 核心概念
| 概念 | 说明 |
|---|---|
| Lease ID | 租约的唯一标识符,由 etcd 分配。 |
| TTL(Time To Live) | 租约的生存时间,单位为秒。如果在此时间内未收到续约请求,租约将过期。 |
| 续约(KeepAlive) | 客户端通过 gRPC stream 定期发送续约请求,重置租约的 TTL。 |
| 关联 Key | 通过 Put 操作将 key 与 Lease ID 绑定。租约过期时,这些 key 会被自动删除。 |
2.4.2 典型应用
- Leader 选举: 候选者创建一个 TTL 较短的租约,并关联一个 key。成功创建 key 的节点成为 Leader,并通过续约保持领导地位。如果 Leader 宕机,租约过期,key 被删除,其他节点可以重新竞选。
- 会话管理: 在分布式系统中,使用租约来管理客户端会话。客户端通过续约表示自己“活着”,一旦断开,关联的临时数据自动清理。
2.5 机制协同关系
这四大机制并非孤立运行,而是紧密协作,共同构成了 etcd 的强一致性、高可用和事件驱动能力:
- Raft + MVCC: Raft 保证日志条目在集群中一致复制,MVCC 则负责将这些日志条目以多版本的形式应用到状态机,提供历史快照能力。
- MVCC + Watch: MVCC 的 revision 为 Watch 提供了精确的事件定位点。Watch 可以基于 revision 进行事件回溯,实现“断点续传”。
- Lease + Raft: Lease 的创建、续约和过期本身也是通过 Raft 日志进行复制的,确保租约状态在集群中一致。
- Lease + Watch: 当租约过期导致 key 被删除时,会触发一个 DELETE 事件,Watch 机制可以捕获该事件并通知客户端。
压测启示: 在压测沙盘中进行资源变更时,需要同时关注 Raft 的选举和复制延迟、MVCC 的版本堆积和压缩效率、Watch 的事件推送吞吐量以及 Lease 的续约成功率。任何一个环节出现瓶颈,都会影响整个系统的稳定性和一致性。