引言

在分布式系统中,如何让多个节点就某个值达成一致,是计算机科学中最核心的挑战之一。Raft 共识算法由 Diego Ongaro 和 John Ousterhout 于 2014 年提出,以其可理解性为首要设计目标,相比 Paxos 更易学习、更易工程实现,从而迅速成为 etcd、Consul、TiKV 等主流分布式系统的底层共识引擎。

本文将从 Raft 的核心设计出发,深入解析 Leader 选举、日志复制、安全性保证三大机制,并探讨实际工程中的性能优化策略。

1. 共识问题与 Raft 设计哲学

共识问题(Consensus Problem)要求一组节点就一个值达成一致,且需满足三个核心属性:

  • 终止性(Termination):每个正常节点最终都会决定某个值。
  • 协定性(Agreement):所有正常节点决定同一个值。
  • 有效性(Validity):最终决定的值必须由某个节点提出。

Raft 的设计哲学是"Strong Leader"模型:所有客户端请求都经由 Leader 处理,Leader 将操作序列化为复制日志(Replicated Log),通过投票机制保证多数派持久化后提交。这种设计与 Paxos 的"Decentralized"路径形成鲜明对比——Raft 用更强的一致性结构换取了显著更低的心智负担。

2. 节点状态与任期机制

Raft 中每个节点始终处于三种状态之一:

  • Leader:处理所有客户端请求,定期发送心跳维持权威。一个任期内至多一个 Leader。
  • Follower:被动响应 Leader 和 Candidate 的请求。若选举超时未收到心跳,即转为 Candidate。
  • Candidate:发起选举,收集多数派选票。获得多数票即当选 Leader。

任期(Term)是 Raft 的逻辑时钟,用单调递增的整数标识。每个节点持久化存储当前任期号 currentTerm,通信时附带此字段。若节点发现自己的任期落后,立即更新;若 Leader 或 Candidate 发现更高任期,即退位为 Follower。任期机制天然杜绝了"僵尸 Leader"问题——旧任期的 Leader 无法在多数派上完成提交,因为它的 RPC 会被更高任期的节点拒绝。

3. Leader 选举

Leader 超时时(默认 150-300ms),Follower 转为 Candidate 并发起选举:

  1. 自增当前任期 currentTerm += 1。
  2. 为自己投票(votedFor = selfId)。
  3. 重置选举定时器。
  4. 向所有其他节点并行发送 RequestVote RPC。

每个节点每任期至多投一票(First-come-first-served),仅在以下情况投赞成:

  • Candidate 的日志至少一样新(比较最后日志条目的 term + index)。
  • 投票尚未投给其他 Candidate。

"日志至少一样新"规则防止数据丢失:若 Candidate 的日志比投票者旧,说明它可能缺少已提交的条目,不允许当选。

选票分裂问题:多个 Follower 同时超时转为 Candidate,各自获得部分选票,无人获得多数派(N/2+1)。此时 Raft 通过随机超时分散下一次选举时机,极大降低选票分裂概率。实践中通常从 [T, 2T] 区间随机选择超时时间。

4. 日志复制

Leader 当选后开始处理客户端请求:

  1. 将客户端操作追加为新的日志条目(未提交状态)。
  2. 并行向所有 Follower 发送 AppendEntries RPC。
  3. 等待多数派成功响应后,提交该条目(更新 commitIndex)。
  4. 返回结果给客户端。
  5. 下次 AppendEntries 携带新的 commitIndex,通知 Follower 提交。

每个日志条目包含:

  • term:创建该条目的 Leader 任期。
  • index:条目在日志中的位置(从 1 开始递增)。
  • command:状态机命令(如 KV 写的 key-value 操作)。

日志一致性检查:AppendEntries RPC 包含 prevLogIndex 和 prevLogTerm,Follower 必须匹配才接受,否则返回冲突信息。若 Leader 通过 nextIndex 回退机制步步收敛,最终使 Follower 日志与 Leader 一致。

5. 安全性保证

5.1 选举限制

Raft 保证 Leader 拥有所有已提交条目(Leader Completeness Property)。这通过两个规则保证:

  • 日志条目只能从 Leader 流向 Follower,Leader 绝不覆盖已有条目。
  • 选举时 Candidate 必须获得多数派投票,而已提交条目也持久化于多数派,故每个投票者都拥有该 Candidate 所有已提交条目——至少与 Candidate 一样新。

5.2 提交前任期条目

Raft 不允许通过计数复制提交前任期条目(Entries from Previous Terms)。这是原论文中最精妙的规则之一:

考虑一个反例:若某条目在前任期被复制到多数派但未被感知提交,直接复制计数提交可能覆盖新 Leader 已写入但未提交的新条目。规则要求:只有当前任期的条目才能通过计数复制提交——间接提交前任期条目(当新条目提交时,前任期条目在多数派上自然也被提交了)。

5.3 Leader 崩溃处理

Leader 崩溃后可能出现:

  • 客户端请求未复制到多数派 → 新 Leader 无此条目,客户端需重试。
  • 已复制但未通知客户端 → 新 Leader 可能重复应用(需幂等或去重)。
  • Follower 日志比新 Leader 长 → 通过回退机制截断并同步。

6. 集群成员变更

线上系统必须支持节点扩缩容。Raft 使用 Joint Consensus(联合共识)实现平滑变更:

  1. Leader 发送 Cold,new 联合配置条目。
  2. 在联合配置期间,所有决策需同时获得 Cold 和 Cnew 的多数派同意。
  3. 联合配置提交后,发送 Cnew 条目完成切换。

联合共识确保变更中间状态不会产生两个独立多数派,避免脑裂。单节点变更(每次增减一个节点)是联合共识的简化形式——无需显式切换阶段,直接计算新配置。

7. 工程优化实践

7.1 批处理与流水线

原始 Raft 每次 AppendEntries 发送一个条目。工程实践中:

  • 批量发送:累积多个条目后一并发送,减少网络往返。
  • 流水线(Pipelining):不等上一次响应,继续发送后续 AppendEntries,提升带宽利用率。
  • AppendEntries 压缩:携带较小的条目以减少传输开销。

7.2 日志压缩与快照

长运行系统日志无限增长不可持续。Raft 使用快照(Snapshot)机制:

  • Leader 定期将状态机状态打包为快照,包含最后包含的 index 和 term。
  • 快照发送给落后较多的 Follower(InstallSnapshot RPC)。
  • 快照删除已持久化的旧日志条目。

7.3 线性一致读

简单读取 Leader 的本地状态可能读到旧数据(若 Leader 身份已变更)。Raft 提供两种线性一致读:

  • ReadIndex:Leader 广播心跳确认多数派响应后,读取本地状态机。
  • LeaseRead:Leader 持有时间租约(< 选举超时),租约期内可直接读本地状态机(更高效的读路径)。

8. 与 Paxos 的深度对比

维度RaftMulti-Paxos
设计哲学Strong Leader, 清晰结构灵活角色, 理论简洁
可理解性高(论文明确优化此目标)低(复杂且难以驾驭)
日志模型连续日志,不允许空洞允许空洞(需额外处理)
Leader 选举内置,确定性超时触发需额外实现
实现难度约2000行(典型工程实现)变量极大
生产案例etcd, Consul, TiKV, CockroachDBChubby, Spanner, ZooKeeper

Raft 的成功并非来自理论突破,而是来自工程可理解性的极致追求。研究表明,学生在学习共识算法时,Raft 的理解速度和正确率均显著优于 Paxos。

9. Raft 在现代系统中的演化

随着硬件演进,Raft 实现也在变化:

  • JRaft / SOFAJRaft:蚂蚁金服基于 Java 的 Raft 实现,支持多组 Raft Group,广泛用于分布式元数据管理。
  • etcd/raft:CoreOS 使用该库构建 etcd,经过 Kubernetes 严苛的生产验证。
  • TiKV Raft:PingCAP 研发的 Multi-Raft 机制,单存储节点支持数千 Raft Group。
  • io_uring + Raft:随着 Linux io_uring 普及,新一代 Raft 实现利用异步 I/O 大幅降低磁盘提交延迟。

10. 总结

Raft 通过三大核心机制构建了完整的共识解决方案:

  • Leader 选举 + 随机超时 → 快速选主、避免选票分裂。
  • 日志复制 + 多数派提交 → 强一致性、线性化语义。
  • 安全性约束 + 任期机制 → 杜绝脑裂、防止数据丢失。

理解了 Raft,你就掌握了现代分布式系统协同运作的底层语言。无论是配置中心、元数据存储,还是 NewSQL 数据库,共识算法都是其不可或缺的基石。

参考文献

  • Ongaro D, Ousterhout J. In Search of an Understandable Consensus Algorithm. USENIX ATC 2014.
  • Raft Consensus Algorithm 官方可视化: raft.github.io
  • etcd Raft 实现分析: etcd.io
  • 《Designing Data-Intensive Applications》第9章: Martin Kleppmann
点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部