3. etcd 基础架构:Raft 共识算法、存储引擎、MVCC 与 Watch 机制

etcd 作为云原生领域的“基石数据库”,其核心架构围绕强一致性、高可用与高性能 Watch 三大目标设计。本章深入拆解 etcd 的四大核心支柱:Raft 共识算法、bbolt 存储引擎、MVCC 事务模型以及 Watch 机制,为后续压测与故障诊断建立坚实的理论基础。

3.1 Raft 共识算法:etcd 的“决策大脑”

Raft 是 etcd 实现分布式数据一致性的核心算法。它将共识问题分解为 Leader 选举、日志复制 和 安全性 三个子问题。在 etcd 集群中,所有写请求必须由 Leader 节点处理,并通过日志复制同步至 Follower 节点。

关键角色: Leader(处理写请求与日志复制)、Follower(被动同步)、Candidate(选举阶段临时角色)。
Raft 共识算法核心流程 Leader 处理所有写请求 Follower 被动同步日志 Follower 被动同步日志 日志复制:Leader 将写请求封装为 Log Entry,通过 AppendEntries RPC 并行发送至所有 Follower 当多数节点(Quorum)持久化日志后,该 Entry 进入 Committed 状态 Leader 选举流程 Follower 超时未收到心跳 → 转为 Candidate → 发起 RequestVote RPC → 获得多数票 → 成为新 Leader

3.1.1 日志复制与 Quorum 机制

etcd 的写性能与集群大小强相关。Raft 要求每次写入必须获得 Quorum(多数节点) 确认,公式为 Quorum = N/2 + 1。下表展示了不同集群规模下的容错能力与性能特征:

集群节点数 Quorum 大小 最大容错节点数 写性能特征
3 2 1 基准性能,延迟适中
5 3 2 延迟增加约 20-30%,吞吐下降
7 4 3 网络开销显著,不推荐生产
压测启示: 在 Cilium 网络故障场景下,Leader 节点网络延迟升高会直接拖慢所有写请求,因为 Follower 的 AppendEntries 响应超时可能导致 Leader 降级或触发选举风暴。

3.2 bbolt 存储引擎:单机持久化基石

etcd v3 使用 bbolt(原 boltdb 的 Go 实现)作为底层存储引擎。bbolt 是一个嵌入式、事务性的键值存储引擎,基于 B+ 树 数据结构实现。

3.2.1 bbolt 核心特性

  • B+ 树索引: 所有键值对按 Key 的字典序存储在 B+ 树中,支持高效的范围查询与顺序遍历。
  • ACID 事务: 支持读事务(可并发)和写事务(独占锁),写事务在提交时通过 mmap 刷盘。
  • 单文件存储: 整个数据库存储在一个 .db 文件中,通过 mmap 映射到内存,减少系统调用。
  • 无 WAL 分离: bbolt 将 WAL 与数据文件合并,简化了崩溃恢复逻辑。
bbolt B+ 树存储结构 Root Page Internal Node Internal Node Internal Node Leaf Page (KV) Leaf Page (KV) Leaf Page (KV) Leaf Page (KV) Leaf Page 叶子节点通过指针形成双向链表,支持高效范围扫描

3.3 MVCC 与事务模型

etcd v3 引入 多版本并发控制(MVCC) 来支持高并发读写。每个键的每次修改都会生成一个新的版本号(revision),旧版本数据不会被立即删除,而是保留一段时间供历史查询或 Watch 使用。

3.3.1 版本号与 KeyValue 结构

etcd 内部使用全局递增的 revision 作为版本号。每个 KeyValue 记录包含以下核心字段:

字段 说明 作用
key 用户存储的键 唯一标识
value 用户存储的值 业务数据
create_revision 创建时的 revision 标识创建版本
mod_revision 最后一次修改时的 revision 标识最新版本
version 该键被修改的次数 从 1 开始递增

3.3.2 事务模型:Txn

etcd 的事务通过 Txn 接口实现,支持 if-then-else 语义。事务内部包含一个判断条件列表、一个成功操作列表和一个失败操作列表。

// etcd 事务示例:CAS(Compare-And-Swap)
txn := client.Txn(ctx)
txn.If(
    client.Compare(client.Value("key1"), "=", "old_value"),
)
txn.Then(
    client.OpPut("key1", "new_value"),
)
txn.Else(
    client.OpGet("key1"),
)
resp, err := txn.Commit()
性能陷阱: 在压测中,过大的事务(包含大量操作)会长时间持有 bbolt 写锁,导致其他请求排队。建议单次事务操作数控制在 128 以内。

3.4 Watch 机制:事件驱动的核心

Watch 是 etcd 实现服务发现、配置变更通知的关键机制。客户端通过 Watch 监听特定 Key 或前缀,当数据发生变化时,etcd 将事件推送给客户端。

3.4.1 Watch 实现原理

  • 基于 MVCC 版本号: Watch 从指定的 revision 开始,向后扫描事件。
  • 事件缓冲区: 每个 Watch 对应一个事件缓冲区(默认 16 个事件),当缓冲区满时,旧事件会被丢弃,客户端需重新同步。
  • 流式 gRPC: Watch 通过 gRPC 双向流实现,etcd 持续推送事件,客户端发送 ACK 控制背压。
etcd Watch 事件推送流程 Client Watch(key) etcd Server WatchableStore bbolt B+ Tree 事件推送流程 1. Client 发起 Watch 请求,指定 Key 和起始 revision 2. etcd 在 bbolt 中扫描 revision 之后的事件,放入事件缓冲区 3. 通过 gRPC 流持续推送事件;Client 发送 ACK 控制流速

3.4.2 Watch 性能关键指标

指标 说明 压测关注点
Watch 数量 集群中活跃的 Watch 连接数 超过 10k 时可能触发内存压力
事件延迟 从数据变更到事件到达客户端的时间 网络故障下延迟可能飙升到秒级
事件积压 事件缓冲区中未推送的事件数 积压过多会导致客户端重新同步
Watch 恢复 客户端断连后重新 Watch 的耗时 Cilium 网络抖动时频繁触发恢复
故障诊断线索: 当 Cilium 网络出现丢包或延迟抖动时,Watch 事件可能丢失或延迟。客户端应实现重连与 revision 校验逻辑,避免因事件缺失导致状态不一致。