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 的心跳,它会发起选举:

  1. 增加本地任期号,转换为 Candidate。
  2. 投票给自己,并向其他节点并行发送 RequestVote RPC。
  3. 如果获得超过半数(n/2 + 1)节点的投票,则成为新的 Leader。
  4. 新 Leader 立即发送心跳(AppendEntries RPC)给所有节点,确立权威并阻止新的选举。

2.1.3 日志复制

这是 Raft 的核心流程,确保所有节点状态一致:

  1. 客户端请求 发送到 Leader。
  2. Leader 将操作追加到本地日志,状态为 未提交(Uncommitted)。
  3. Leader 并行向所有 Follower 发送 AppendEntries RPC,包含日志条目。
  4. Follower 收到后追加日志,并回复成功。
  5. Leader 收到超过半数的成功回复后,将日志条目标记为 已提交(Committed),并应用到状态机。
  6. Leader 在后续的心跳中通知 Follower 该条目已提交,Follower 随后应用到自己的状态机。
安全性保证: Raft 通过“选举限制”确保只有拥有最新日志的节点才能成为 Leader,通过“日志匹配特性”保证所有已提交的日志条目在集群中具有相同的顺序和内容。
Raft 日志复制流程 Client Leader Follower 1 Follower 2 ① 写请求 追加本地日志 ② AppendEntries ② AppendEntries ③ 回复成功 ③ 回复成功 提交并应用 ④ 心跳通知提交 ④ 心跳通知提交 关键点:Leader 在收到多数派(此处为 2/3)成功回复后,才提交日志并通知所有 Follower。

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 工作流程

  1. 注册: 客户端发起 Watch gRPC 请求,指定要监听的 key 或前缀,以及起始 revision。
  2. 事件捕获: etcd 的 WatchableStore 模块监听 MVCC 的写操作。当有匹配的 key 被修改时,生成一个 Event(包含类型 PUT/DELETE 和键值对)。
  3. 推送: WatchableStore 将事件通过 gRPC stream 推送给所有注册了该 key 的客户端。
  4. 重连与恢复: 如果 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 被删除,其他节点可以重新竞选。
  • 会话管理: 在分布式系统中,使用租约来管理客户端会话。客户端通过续约表示自己“活着”,一旦断开,关联的临时数据自动清理。
Lease 生命周期与 Key 关联 Client etcd Cluster Lease (ID: 123) Key: /lock ① Grant(10s) 返回 Lease ID ② Put(key, lease=123) 关联 ③ KeepAlive(每 5s) Lease 过期 (TTL 耗尽) ④ 触发 Lease 失效 ⑤ 级联 Key 删除 关键点:Lease 是分布式系统中的“心跳”机制,用于管理临时数据的生命周期,是实现 Leader 选举和会话管理的基础。

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 的续约成功率。任何一个环节出现瓶颈,都会影响整个系统的稳定性和一致性。