Raft 共识与强一致复制

kp-026 · 分布式与NoSQL前沿约 35 分钟已校对

前置知识点

前置:

相关知识点

相关:

学习进度:

一句话定义

Raft 是把共识(Consensus)拆解为「选主(Leader Election)+ 日志复制(Log Replication)+ 安全性约束」三件事的可理解算法:多数派确认日志后提交,使一组节点对外表现为一台永不丢提交数据的逻辑主机。

为什么重要

前置知识

kp-025(线性一致与分区权衡)、kp-023(复制与故障切换问题)。

核心概念

原理与机制

选举:Candidate 自增 term、给自己投票并拉票;获得多数派即当选——「多数派」保证任意两个多数派有交集,新旧 Leader 必然交接过完整日志。日志复制:Leader 接受写请求先追加本地日志,并行发送 AppendEntries 给 Followers,多数派 ack 后提交并通知应用。安全性由选举限制闭环:若某已提交条目只在一部分节点上,落选者不可能胜出,因为它比多数派「旧」。分区下的行为(与 kp-025 呼应):少数派分区中的旧 Leader 收不到多数派心跳、无法提交任何写——这正是 CAP 中选 C 的自动化实现;分区恢复后旧 Leader 看到更高 term 立即退位。对比 2PC:Raft 的「协调者」本身被多数派复制,故障切换毫秒级且不悬挂锁;对比 kp-023 的异步主从:Raft 的提交语义是多数派持久化,主库宕机零丢失。性能代价:每次写至少一次多数派 RTT + fsync,跨机房部署时延迟显著。

实例或案例

TiKV 的 Region(Range 分区,kp-024)每个是一个 Raft 组(通常 3 副本):写请求路由到 Region Leader,多数派落盘后提交;某节点宕机,剩余两节点多数派仍在,自动选出新 Leader,业务侧表现为毫秒级抖动。etcd 用单 Raft 组存储集群元数据,Kubernetes 所有资源对象经它强一致读写——「3 节点坏 1 个不影响服务」正是多数派的日常体验。读优化案例:高频配置读用 ReadIndex——Leader 先向多数派发一次心跳确认自己未被罢免,再本地读,省去日志写入,读吞吐提高一个量级且保持线性一致。

常见误区

自测题

  1. 为什么 Raft 要求「投票给日志至少与自己一样新的候选者」? 答:保证当选 Leader 必然持有全部已提交条目(新日志定义含更高 term 或同 term 更长索引),提交过的数据在换主后绝不回滚。
  2. 分区期间少数派侧的 Leader 为什么写不进去? 答:写入需要多数派持久化确认,少数派凑不齐多数派;它也无法提交选出的任何新 term,恢复后立即退位。

公式或模型

可用性:N = 2f+1 副本容忍 f 个故障;写延迟 ≈ 1 RTT(多数派) + fsync;读延迟(租约内)≈ 本地 RTT ≈ 0。选举风暴控制:随机超时区间 [T, 2T] 使瓜分选票概率趋近 0。

图示

Leader (term 5) Follower A Follower B Follower C(分区隔离) append append A、B 确认 = 多数派(2/3)→ 提交 C 落后,恢复后按日志补齐并接受新任期
Raft:写请求由 Leader 复制到多数派即提交;被隔离节点既不能提交也不会分叉

直观类比

Raft 像三人乐队定的规矩:任何新乐谱(写)必须三人中至少两人抄到手并确认才算定稿(提交);指挥(Leader)一旦联系不上两名队友就自动降为队员,大家重新投票——票数规则保证新指挥手里的谱至少和旧指挥一样全。

与其他知识点的关系

kp-018 的 2PC 是「参与者各自单机」的跨库协议,Raft 则先让「一组节点」变成一台可靠机器再谈事务(Spanner 式路线);kp-023 的手动切换与 fencing 被 Raft 的 term 机制内建;kp-024 的每个分区可独立成一个 Raft 组。

延伸阅读