etcd 架构与 Raft 协议:核心组件与一致性原理

etcd 是一个高可用的分布式键值存储系统,其核心设计围绕 强一致性 与 高可用性 展开。理解 etcd 的整体架构以及底层的 Raft 共识协议,是进行高效客户端开发和精准压测的前提。本章将拆解 etcd 的内部组件,并深入 Raft 协议的选举与日志复制机制。

2.1 etcd 整体架构:分层与协作

etcd 采用分层架构设计,从上到下依次为客户端层、API 层、Raft 共识层、存储层和持久化层。各层职责清晰,通过接口协作。

架构要点: etcd 的 gRPC 网关层负责接收客户端请求,Raft 层保证集群数据一致性,WAL 和 Snapshot 则确保数据的持久化与快速恢复。
etcd 整体架构分层图 etcd 整体架构分层图 Client (etcdctl / SDK / gRPC 客户端) gRPC API (v3 接口 / 认证 / 拦截器) Raft 共识模块 Leader 选举 / 日志复制 / 状态机 存储引擎 (BoltDB / 内存索引 / MVCC) 持久化层 WAL (预写日志) | Snapshot (快照) 说明: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 并发起选举:

  1. 发起选举:Candidate 增加当前任期号,投票给自己,并向其他节点发送 RequestVote RPC。
  2. 投票规则:每个节点在一个任期内只能投一票,且优先投票给日志更完整的 Candidate。
  3. 赢得选举:Candidate 获得超过半数(N/2+1)节点的投票,成为新 Leader。
  4. 心跳广播:新 Leader 立即发送心跳(AppendEntries RPC)给所有节点,确立权威。
Raft 选举与日志复制流程 Raft 选举与日志复制流程 Leader 选举流程 Follower 超时 转为 Candidate 发起投票请求 获得多数票 → Leader 日志复制流程 Client 写请求 Leader 追加日志 并行复制到 Follower 多数确认 → 提交 关键点:选举需要多数派同意;日志复制也需要多数派确认后才算提交成功

2.2.3 日志复制与提交

所有写操作必须通过 Leader 处理,流程如下:

  1. 追加日志:Leader 将客户端请求包装为日志条目,追加到本地日志。
  2. 并行复制:Leader 通过 AppendEntries RPC 将日志并行发送给所有 Follower。
  3. 多数确认:当 Leader 收到超过半数节点的成功响应后,日志条目进入 已提交 状态。
  4. 应用到状态机:Leader 将已提交的日志应用到状态机(BoltDB),并通知 Follower 应用。
  5. 响应客户端: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 节点重启时,恢复顺序为:

  1. 从最新的 Snapshot 文件加载状态机快照。
  2. 从 Snapshot 之后的 WAL 文件重放所有日志条目。
  3. 应用日志到状态机,恢复到崩溃前的状态。
压测建议: 在压测集群中,可以手动触发 Snapshot(通过 etcdctl snapshot save)来观察其对写入延迟的影响。高频率的 Snapshot 会消耗磁盘 IO,建议根据业务场景调整 --snapshot-count 参数。

2.4 本章小结

  • etcd 架构分为 Client、gRPC API、Raft 共识、存储引擎和持久化层,各层职责明确。
  • Raft 协议通过 Leader 选举和日志复制保证强一致性,选举需要多数派同意,日志复制也需要多数派确认。
  • WAL 保证数据持久化,Snapshot 控制日志体积,两者共同支撑 etcd 的高可用与快速恢复。
  • 在压测中,需重点关注 Leader 选举事件、日志复制延迟和 WAL fsync 性能,这些是影响 etcd 吞吐和延迟的关键因素。