etcd 架构与 Raft 协议:核心组件与一致性原理
etcd 是一个高可用的分布式键值存储系统,其核心设计围绕 强一致性 与 高可用性 展开。理解 etcd 的整体架构以及底层的 Raft 共识协议,是进行高效客户端开发和精准压测的前提。本章将拆解 etcd 的内部组件,并深入 Raft 协议的选举与日志复制机制。
2.1 etcd 整体架构:分层与协作
etcd 采用分层架构设计,从上到下依次为客户端层、API 层、Raft 共识层、存储层和持久化层。各层职责清晰,通过接口协作。
架构要点: etcd 的 gRPC 网关层负责接收客户端请求,Raft 层保证集群数据一致性,WAL 和 Snapshot 则确保数据的持久化与快速恢复。
2.1.1 核心组件职责
| 组件层 | 核心模块 | 主要职责 |
|---|---|---|
| Client | etcdctl / SDK / gRPC 客户端 | 发起 KV 操作、Watch、Lease 请求;负责负载均衡与连接管理 |
| gRPC API | v3 API / 认证 / 拦截器 | 接收客户端请求,进行身份验证、请求限流、请求路由 |
| Raft 共识 | Leader 选举 / 日志复制 / 状态机 | 保证集群节点间数据一致,是 etcd 高可用的核心 |
| 存储引擎 | BoltDB / 内存索引 / MVCC | 管理键值数据的存储、索引与多版本并发控制 |
| 持久化层 | WAL / Snapshot | WAL 记录所有操作日志,Snapshot 压缩历史日志,加速恢复 |
2.2 Raft 协议:选举与日志复制原理
Raft 是一种易于理解的分布式共识协议,etcd 使用它来管理集群状态。Raft 将节点角色分为 Leader、Follower 和 Candidate,通过 Leader 选举 和 日志复制 两个核心过程保证一致性。
2.2.1 节点角色与任期
- Leader:负责处理所有客户端请求,管理日志复制,定期发送心跳。
- Follower:被动接收 Leader 的日志和心跳,响应选举请求。
- Candidate:在选举超时后发起选举,争取成为新 Leader。
- Term(任期):每个选举周期为一个任期,任期号单调递增,用于防止脑裂。
压测启示: 在压测中,如果集群发生 Leader 选举,客户端会短暂不可用(通常 50-200ms)。压测脚本应具备重试机制,并记录选举事件对延迟的影响。
2.2.2 Leader 选举过程
当 Follower 在选举超时时间内未收到 Leader 心跳,会转为 Candidate 并发起选举:
- 发起选举:Candidate 增加当前任期号,投票给自己,并向其他节点发送
RequestVote RPC。 - 投票规则:每个节点在一个任期内只能投一票,且优先投票给日志更完整的 Candidate。
- 赢得选举:Candidate 获得超过半数(N/2+1)节点的投票,成为新 Leader。
- 心跳广播:新 Leader 立即发送心跳(AppendEntries RPC)给所有节点,确立权威。
2.2.3 日志复制与提交
所有写操作必须通过 Leader 处理,流程如下:
- 追加日志:Leader 将客户端请求包装为日志条目,追加到本地日志。
- 并行复制:Leader 通过
AppendEntries RPC将日志并行发送给所有 Follower。 - 多数确认:当 Leader 收到超过半数节点的成功响应后,日志条目进入 已提交 状态。
- 应用到状态机:Leader 将已提交的日志应用到状态机(BoltDB),并通知 Follower 应用。
- 响应客户端:Leader 向客户端返回写入成功。
压测注意事项: 日志复制延迟受网络带宽、磁盘 I/O 和集群规模影响。在压测中,应关注
etcd_server_proposals_failed_total 和 etcd_disk_wal_fsync_duration_seconds 指标,它们直接反映 Raft 层的健康度。
2.3 WAL 与 Snapshot:持久化与恢复
etcd 使用 WAL(Write-Ahead Logging) 记录所有状态变更,确保数据不丢失。随着时间推移,WAL 文件会不断增长,etcd 通过 Snapshot 机制压缩历史日志。
| 组件 | 作用 | 触发时机 | 压测关注点 |
|---|---|---|---|
| WAL | 记录所有 Raft 日志条目,崩溃后重放恢复 | 每次写入操作 | WAL fsync 延迟影响写入吞吐 |
| Snapshot | 保存当前状态机快照,删除旧 WAL 日志 | WAL 文件大小超过阈值(默认 10,000 条) | Snapshot 创建期间可能引起 IO 抖动 |
2.3.1 恢复流程
当 etcd 节点重启时,恢复顺序为:
- 从最新的 Snapshot 文件加载状态机快照。
- 从 Snapshot 之后的 WAL 文件重放所有日志条目。
- 应用日志到状态机,恢复到崩溃前的状态。
压测建议: 在压测集群中,可以手动触发 Snapshot(通过
etcdctl snapshot save)来观察其对写入延迟的影响。高频率的 Snapshot 会消耗磁盘 IO,建议根据业务场景调整 --snapshot-count 参数。
2.4 本章小结
- etcd 架构分为 Client、gRPC API、Raft 共识、存储引擎和持久化层,各层职责明确。
- Raft 协议通过 Leader 选举和日志复制保证强一致性,选举需要多数派同意,日志复制也需要多数派确认。
- WAL 保证数据持久化,Snapshot 控制日志体积,两者共同支撑 etcd 的高可用与快速恢复。
- 在压测中,需重点关注 Leader 选举事件、日志复制延迟和 WAL fsync 性能,这些是影响 etcd 吞吐和延迟的关键因素。