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(选举阶段临时角色)。
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 与数据文件合并,简化了崩溃恢复逻辑。
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 控制背压。
3.4.2 Watch 性能关键指标
| 指标 | 说明 | 压测关注点 |
|---|---|---|
| Watch 数量 | 集群中活跃的 Watch 连接数 | 超过 10k 时可能触发内存压力 |
| 事件延迟 | 从数据变更到事件到达客户端的时间 | 网络故障下延迟可能飙升到秒级 |
| 事件积压 | 事件缓冲区中未推送的事件数 | 积压过多会导致客户端重新同步 |
| Watch 恢复 | 客户端断连后重新 Watch 的耗时 | Cilium 网络抖动时频繁触发恢复 |
故障诊断线索: 当 Cilium 网络出现丢包或延迟抖动时,Watch 事件可能丢失或延迟。客户端应实现重连与 revision 校验逻辑,避免因事件缺失导致状态不一致。