引言
在分布式系统中,如何让多个节点就某个值达成一致,是计算机科学中最核心的挑战之一。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 并发起选举:
- 自增当前任期
currentTerm += 1。 - 为自己投票(
votedFor = selfId)。 - 重置选举定时器。
- 向所有其他节点并行发送
RequestVoteRPC。
每个节点每任期至多投一票(First-come-first-served),仅在以下情况投赞成:
- Candidate 的日志至少一样新(比较最后日志条目的 term + index)。
- 投票尚未投给其他 Candidate。
"日志至少一样新"规则防止数据丢失:若 Candidate 的日志比投票者旧,说明它可能缺少已提交的条目,不允许当选。
选票分裂问题:多个 Follower 同时超时转为 Candidate,各自获得部分选票,无人获得多数派(N/2+1)。此时 Raft 通过随机超时分散下一次选举时机,极大降低选票分裂概率。实践中通常从 [T, 2T] 区间随机选择超时时间。
4. 日志复制
Leader 当选后开始处理客户端请求:
- 将客户端操作追加为新的日志条目(未提交状态)。
- 并行向所有 Follower 发送
AppendEntriesRPC。 - 等待多数派成功响应后,提交该条目(更新
commitIndex)。 - 返回结果给客户端。
- 下次
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(联合共识)实现平滑变更:
- Leader 发送
Cold,new联合配置条目。 - 在联合配置期间,所有决策需同时获得
Cold和Cnew的多数派同意。 - 联合配置提交后,发送
Cnew条目完成切换。
联合共识确保变更中间状态不会产生两个独立多数派,避免脑裂。单节点变更(每次增减一个节点)是联合共识的简化形式——无需显式切换阶段,直接计算新配置。
7. 工程优化实践
7.1 批处理与流水线
原始 Raft 每次 AppendEntries 发送一个条目。工程实践中:
- 批量发送:累积多个条目后一并发送,减少网络往返。
- 流水线(Pipelining):不等上一次响应,继续发送后续
AppendEntries,提升带宽利用率。 - AppendEntries 压缩:携带较小的条目以减少传输开销。
7.2 日志压缩与快照
长运行系统日志无限增长不可持续。Raft 使用快照(Snapshot)机制:
- Leader 定期将状态机状态打包为快照,包含最后包含的
index和term。 - 快照发送给落后较多的 Follower(
InstallSnapshotRPC)。 - 快照删除已持久化的旧日志条目。
7.3 线性一致读
简单读取 Leader 的本地状态可能读到旧数据(若 Leader 身份已变更)。Raft 提供两种线性一致读:
- ReadIndex:Leader 广播心跳确认多数派响应后,读取本地状态机。
- LeaseRead:Leader 持有时间租约(< 选举超时),租约期内可直接读本地状态机(更高效的读路径)。
8. 与 Paxos 的深度对比
| 维度 | Raft | Multi-Paxos |
|---|---|---|
| 设计哲学 | Strong Leader, 清晰结构 | 灵活角色, 理论简洁 |
| 可理解性 | 高(论文明确优化此目标) | 低(复杂且难以驾驭) |
| 日志模型 | 连续日志,不允许空洞 | 允许空洞(需额外处理) |
| Leader 选举 | 内置,确定性超时触发 | 需额外实现 |
| 实现难度 | 约2000行(典型工程实现) | 变量极大 |
| 生产案例 | etcd, Consul, TiKV, CockroachDB | Chubby, 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

发表评论 取消回复