Skip to content

分布式共识协议 Raft

角色与任期、Leader 选举机制、多数派日志复制、脑裂防范与安全性规则(选举限制与提交限制)。

Updated View as Markdown
For humans

分布式共识协议 Raft

校招考察频度:☆ 中频(重点常考·大厂分水岭) 一句话速记:Raft 将复杂的分布式共识拆解为三大子问题(Leader 选举、日志复制、安全性);通过随机超时破除选举分票,依靠多数派原则(过半 N/2+1 确认)保障可用,以“日志更全者方可当选”杜绝已提交数据丢失,用单调任期 Term 天然平息脑裂。

在分布式系统面试中,Paxos 算法因为晦涩难懂几乎很少被直接考源码,而Raft 作为工业界事实上的统一标准(etcd、Consul、TiKV、Kafka KRaft 全在用),是面试官考察分布式一致性的最爱。


一、0 基础直观理解:班级记账与选班长模型

如果把一个分布式集群比作**“一个共同记账的班级”**:

Raft 概念生活化比喻现实运行逻辑
Leader(领导者)正班长全班唯一的记账人,负责接纳外界所有转账指令,并命令其他同学同步抄写。
Follower(跟随者)普通同学平时只安静听班长指挥并抄写账本,定时接收班长的“我还在工作”的心跳。
Candidate(候选人)竞选班长当普通同学很久没收到班长消息(超时)时,怀疑班长病退,举手自荐竞选新班长并拉票。
Term(任期)学年届数(第 1 届、第 2 届…)单调递增的逻辑时钟。任何节点只要看到比自己高的 Term,立刻自愿听从对方。
多数派(Quorum)过半数同学举手表决(N/2 + 1)只要超过半数同意,决议就具有不可推翻的全局法律效力。

二、三大子问题之一:Leader 选举与随机超时

Raft 节点状态机流转与选举时序

1. 为什么选举超时时间(Election Timeout)必须是随机的?

  • 痛点:选票瓜分(Split Vote)死锁:如果所有节点的超时时间都是固定的 200ms,一旦 Leader 宕机,所有 Follower 将在同一微秒同时发起竞选,各自给自己投一票,最终谁也无法获得过半票数,选举陷入无限僵局!
  • 解决方案:随机化(Randomized Timeout):将每个节点的超时时间打散在 150ms ~ 300ms 之间。跑得最快的节点会率先超时并向其他人发起拉票,在别人刚醒来时就已成功斩获过半选票,单次平滑收敛,零僵局。

三、三大子问题之二:日志复制与两阶段提交

Raft 的核心使命是维护所有节点上**日志复制状态机(Replicated State Machine)**的一致性:

       ┌─────────────────────────────────────────────────────────────┐
       │ 1. 客户端发来写请求: Leader 将命令追加到本地 Log 末尾 (未提交)│
       └──────────────────────────────┬──────────────────────────────┘
                                      ▼
       ┌─────────────────────────────────────────────────────────────┐
       │ 2. 并发广播 AppendEntries: Leader 异步发给所有 Follower      │
       └──────────────────────────────┬──────────────────────────────┘
                                      ▼
       ┌─────────────────────────────────────────────────────────────┐
       │ 3. 多数派落盘确认: 超过半数 (N/2 + 1) 节点写入成功后         │
       │    Leader 正式将该日志标记为【已提交 (Committed)】            │
       └──────────────────────────────┬──────────────────────────────┘
                                      ▼
       ┌─────────────────────────────────────────────────────────────┐
       │ 4. 应用到状态机并响应客户端: 下一次心跳告知 Follower 一同提交 │
       └─────────────────────────────────────────────────────────────┘
  • 过半即成功:5 节点的集群,只要 3 个节点写入成功即可提交,允许 2 个节点临时宕机或网络卡顿,可用性与强一致性兼备。

四、三大子问题之三:核心安全性(已提交日志绝不丢失)

为了杜绝“新当选的 Leader 肚子里没有最新提交的数据”,Raft 制定了两条绝对不可逾越的铁律:

1. 选举限制:日志不全者直接取消当选资格

当 Follower 收到候选人的拉票请求(RequestVote)时,不仅比任期,还必须比对最后一条日志的最新度(Last Log Index & Last Term):

  • 只有候选人的日志**“至少与自己一样新(任期更高,或者任期相同但 index 编号更大)”**时,Follower 才会把票投给它。
  • 数学证明:一条日志被提交,意味着它已经存在于“多数派”节点上;而任何新 Leader 要当选,也必须获得“多数派”的投票。两个多数派集合必定至少相交于 1 个共同节点!这个交集节点必定包含最新的已提交日志,并会直接一票否决那些落后的候选人。

2. 提交限制:Leader 绝不直接提交旧任期的日志

当前 Leader 只能通过计算“当前任期自己产生的日志”是否过半来推进 commitIndex,旧任期的残留日志只能顺带连带提交,防止极端的并发网络乱序覆盖历史数据。


五、脑裂(Split-Brain)如何优雅防范?

原始 5 节点集群发生网络分区:
[Node 1 (旧 Leader), Node 2]  ❌  [Node 3, Node 4, Node 5]
       (少数派分区: 2 节点)               (多数派分区: 3 节点)
  • 少数派分区(2 节点):Node 1 试图写数据,但只有 2 票(未达到 3 票),所有的写入请求永远无法提交,处于阻塞等待。
  • 多数派分区(3 节点):因收不到心跳,Node 3 率先超时,自增 Term 选出新 Leader。拥有 3 票过半优势,正常对外提供读写服务。
  • 网络分区恢复时:旧 Leader(Node 1)收到了新 Leader(Node 3)发来的更高 Term 心跳,立刻心服口服地降级为 Follower,并用新 Leader 的日志截断并覆盖自己的未提交日志。整个集群平滑愈合,从数学上根本不可能出现双主双写的“脑裂”现象!

六、知识脉络关联网(Knowledge Highway)


七、校招高频面试追问

  1. Raft 集群的节点数为什么推荐是奇数(3 或 5 个),而不是偶数?
    • 容错能力由公式决定:NN 个节点最多容忍 (N−1)/2(N - 1) / 2 个节点故障。
    • 3 节点集群能容忍 1 个故障(3→13 \to 1),4 节点集群也只能容忍 1 个故障(因为 4 节点过半需要 3 票,4−3=14 - 3 = 1)。偶数节点不仅没有提升可用性,反而增加了一台服务器的成本与选举平票概率,纯属浪费。
  2. Leader 宕机恢复后,之前已写进本地但未提交的日志怎么处理?
    • 新 Leader 当选后拥有绝对权威。旧 Leader 恢复并作为 Follower 加入后,新 Leader 会在其追加日志的 RPC 中检查一致性索引。如果发现 Follower 的末端日志与自己不符,会强行命令 Follower 截断并删除那些未提交的脏日志,以新 Leader 为准保持全局统一。
Navigation

Type to search…

↑↓ navigate↵ selectEsc close