土法炼钢兴趣小组的算法知识备份

【分布式系统百科】大鹅也能看懂的 Raft 算法解读:选举 · 日志 · 不变量 · 研究前沿

文章导航

分类入口
distributed
标签入口
#raft#consensus#leader-election#log-replication#safety#flexible-paxos#multi-raft#distributed-systems

目录

你要用三台机器共同维护一份配置(或一份键值)。客户端写成功之后,任何一台宕机、任何一次网络抖动,都不能让「已经成功」的写在别的副本上消失或变成另一条命令。这件事乍看像「多备份一下」,做对却意味着在异步网络里解决共识(Consensus)

Raft(Ongaro & Ousterhout, USENIX ATC 2014)把共识问题拆成可单独理解的几块:谁当领导者、怎么复制日志、哪些规则保证永不破坏已提交数据。它故意把「工程师能正确实现」当作一等设计目标,而不是先追求理论上的最大并发。

本文是入门旗舰:场景建直觉、图钉机制、少量公式钉不变量,最后用专章谈近年研究分叉。etcd 的 PreVote、ReadIndex、ConfChange V2 等工程补丁不在此展开,见 Raft 深度重写。协议选型与实测见 共识工程权衡

本文是分布式系统百科的共识阅读入口之一。 正式机制以 ATC 2014 论文与 Ongaro 博士论文为准;工业扩展标注出处等级。

目标 去哪读
先建立正确心智模型 本篇
论文缺口与 etcd/TiKV 工程 raft-deep
Raft vs Multi-Paxos vs EPaxos 17
Flexible / EPaxos 平行路线 14-epaxos

一、问题:三台机器如何对同一条写达成一致

1.1 坏结局场景

客户端 SET x=1,节点 A 返回成功。随后 A 宕机。客户端读到 B 上还是旧值,或更糟:读到 C 上是 x=2,那是另一次未对齐的写。多副本若没有全局唯一的操作顺序,应用层无论怎么重试都会面对互相矛盾的历史。

1.2 复制状态机(Replicated State Machine)

共识算法通常不直接同步「当前状态」,而是同步一份有序日志。只要各节点日志的已提交前缀相同,按相同顺序应用到确定性状态机,最终状态就相同。

复制状态机:客户端写经 Leader 日志复制到 Follower 再应用

需要同时关心两件事:

FLP 不可能结果(Fischer, Lynch, Paterson, 1985)断言:在完全异步模型下,即使只有一个节点可能崩溃,也不存在确定性算法同时保证 Safety 与 Liveness。Raft 的工程折中是:Safety 绝对优先;活性依赖「随机化选举超时 + 多数派最终连通」这类实践假设。详见 FLP 与不可能性

1.3 Raft 如何拆问题

子问题 英文 本文责任
领导者选举 Leader Election 第三节
日志复制 Log Replication 第四节
安全性 Safety 第五节
日志压缩 Snapshot 第六节(短)
成员变更 Membership Change 第六节(短)

相对 classic Paxos 叙述,Raft 把「谁发起提案」收敛为强领导者:稳态下客户端只跟 Leader 说话,Follower 被动复制。代价是 Leader 成为吞吐瓶颈——这正是第八节研究分叉的起点。

1.4 和「主从复制」差在哪里

很多人第一反应是:「不就是选个主库做异步/半同步复制吗?」差在提交语义

典型主从复制 Raft
主库故障 可能丢尚未同步的写;切换策略因产品而异 新 Leader 必须携带已 commit 前缀(Leader Completeness)
「成功」含义 有时只表示主库落盘 表示条目已进入多数派稳定存储且可安全应用
脑裂 双主是常见事故模式 同 term 至多一合法 Leader;旧 Leader 遇更高 term 必须下台
规范完整性 常散落在产品文档与脚本 选举 / 复制 / 安全 / 成员变更写在同一套规则里

半同步复制可以逼近「多数确认再确认客户端」,但很少同时给出选举限制、旧任期提交规则与联合共识的一揽子不变量。Raft 的价值是把这些钉成可教学、可实现、可论证的一体协议。对照阅读:主从复制


二、核心名词:任期、角色、多数派

2.1 任期(Term)

Term 是 Raft 的逻辑纪元:整数,单调递增;每次新选举开始时加一。每个 term 内至多一个 Leader。 节点收到更高 term 的 RPC 时更新本地 term 并退回 Follower;收到更低 term 的 RPC 则拒绝。

任期时间轴:过期消息被拒绝,更高任期迫使下台

2.2 三种角色

stateDiagram-v2
  [*] --> Follower
  Follower --> Candidate: election timeout
  Candidate --> Leader: wins majority votes
  Candidate --> Follower: discovers higher term or loses
  Candidate --> Candidate: split vote then new election
  Leader --> Follower: discovers higher term

2.3 多数派(Quorum)

\(N\) 节点集群的多数派大小为

\[ q = \left\lfloor \frac{N}{2} \right\rfloor + 1 \]

例如 \(N=3\)\(q=2\)\(N=5\)\(q=3\)。任意两个多数派集合的交集非空——这是后文 Leader Completeness 的几何直觉。

日志条目记为三元组 \((\textit{index}, \textit{term}, \textit{command})\)。Leader 还有:


三、Leader 选举:谁来协调写入

3.1 坏结局场景:所有人同时参选

若所有 Follower 使用相同超时、同时发现 Leader 失联,会同时变成 Candidate、互不投票 → 选票分裂(split vote),集群长时间无 Leader,写入全部卡住。

3.2 随机选举超时

每个 Follower 从区间(论文建议约 \(150\)\(300\,\mathrm{ms}\),工程可按 RTT 标定)随机抽取 election timeout。超时未见心跳则:

  1. 当前 term 加一,角色变为 Candidate;
  2. 给自己投票,向同伴发 RequestVote
  3. 若获得多数票 → Leader,立刻发心跳抑制他人超时;
  4. 若发现更高 term 或现成 Leader → 退回 Follower;
  5. 若超时仍无结果 → 再开一轮选举(新 term)。
sequenceDiagram
  participant F1 as Follower_S1
  participant F2 as Follower_S2
  participant F3 as Follower_S3
  Note over F1,F3: Leader missing
  F1->>F1: timeout first
  F1->>F2: RequestVote term=T
  F1->>F3: RequestVote term=T
  F2-->>F1: grant vote
  F3-->>F1: grant vote
  Note over F1: becomes Leader
  F1->>F2: AppendEntries heartbeat
  F1->>F3: AppendEntries heartbeat

随机化把「同时超时」压成小概率事件;论文实验表明合理超时范围内选举通常一轮结束。

3.3 三节点选举走查

设集群 \(\{S_1,S_2,S_3\}\),原 Leader \(S_1\) 失联。

时刻 \(S_2\) \(S_3\) 结果
\(t_0\) 超时抽到 \(170\,\mathrm{ms}\) 抽到 \(240\,\mathrm{ms}\) 仍为 Follower
\(t_0+170\,\mathrm{ms}\) 升为 Candidate,term \(\leftarrow T+1\),自投 1 票 仍等超时 \(S_2\) 发出 RequestVote
收到 \(S_3\) 同意(假设日志足够新) 授票后重置超时 \(S_2\) 获 2 票=多数 → Leader
发送心跳 收到心跳,保持 Follower 集群恢复可写

\(S_2\)\(S_3\) 几乎同时超时且互不投票,本轮无人胜出;各自再次随机超时后重试。工程调参要点:

3.4 投票规则里的安全阀门

Follower 或 Candidate 授予选票时至少检查:

  1. 候选人 term 不低于自己,且本 term 尚未把票投给别人;
  2. 选举限制(Election Restriction):候选人日志「至少与投票者一样新」。

「一样新」的比较顺序(论文定义):

  1. 先比双方日志最后一条的 term,更大者更新;
  2. term 相同再比最后一条的 index,更大者更新。

没有这条限制,日志严重落后的节点可能当选,随后用自己的日志覆盖已提交前缀——Safety 直接破裂。

用数字感受一次:

按规则先比 term:\(4<5\),候选人更旧,即使 index 更大也不能获票。这避免「靠灌大量未提交的旧任期条目骗选」。

3.5 多数派交集直觉

多数派交集:提交仲裁与选举仲裁必有公共节点

Committed 条目一定落在某个多数派磁盘(或稳定存储)上;新 Leader 也由某个多数派选出。公共节点若遵守选举限制,就不会把选票交给「比已提交历史更旧」的候选人——这是第五节证明的脚手架。


四、日志复制:写入如何变成集群事实

4.1 一条写的正常路径

  1. Client 把命令发给 Leader(Follower 可重定向)。
  2. Leader 在本地日志末尾追加条目(当前 term)。
  3. 并行向 Follower 发 AppendEntries(可批量)。
  4. 多数节点持久化成功后,Leader 推进 commitIndex,回复 Client。
  5. 各节点把 lastApplied..commitIndex 应用到状态机。
sequenceDiagram
  participant C as Client
  participant L as Leader
  participant F as Follower
  C->>L: Write command
  L->>L: append local log
  L->>F: AppendEntries
  F-->>L: success
  Note over L: majority reached
  L->>L: commitIndex++
  L-->>C: OK
  L->>L: apply to state machine
  F->>F: apply when notified

心跳是空的 AppendEntries,作用是重置 Follower 超时、捎带最新 commitIndex

4.2 一致性检查与日志匹配

每条 AppendEntries 携带 prevLogIndexprevLogTerm。Follower 必须在该位置有相同 term 的条目,否则拒绝。拒绝后 Leader 回退(论文逐步减一;生产实现常根据冲突 term 跳跃——见 deep 文)。

这保证 Log Matching Property:若两份日志在同一 index 上 term 相同,则该 index 及之前的所有条目都相同。

日志冲突修复:Follower 截断冲突后缀后对齐 Leader

4.3 论文 Figure 8:为何不能「有多数就提交旧任期条目」

直觉上「多数副本已写入即可 commit」。对当前 term 的条目这通常成立;对旧 term 的条目,若 Leader 直接按多数提交,会在领导者频繁更迭时踩雷。论文 Figure 8 给出的反例轮廓如下。

Figure 8 四格:错误提交规则如何毁掉已提交数据

口头推演(5 节点):

  1. (a) S1 在 term 2 于 index 2 写入条目,只复制到 S2,未达多数即宕机。
  2. (b) S5 当选 term 3,在 index 2 写入另一条(term 3),仅本地存在后宕机。
  3. (c) 错误规则:S1 恢复并当选 term 4,把 index 2 的 term-2 条目复制到多数后立刻 commit。之后 S5 仍可能凭「更新的 term-3 日志」当选,并用 term-3 条目覆盖 index 2——已 commit 的命令被抹掉
  4. (d) 正确规则:Leader 只对当前 term 的条目用多数派推进 commit;旧 term 条目通过「更高 index 的当前 term 条目先 commit」被间接提交。生产里常见做法是新 Leader 立刻追加一条 no-op(空命令)以尽快完成间接提交。

手填日志表(建议先遮住答案自己填)

单元格写 index/term;空白表示该位置尚无条目。命令语义:A = term-2 在 index 2 的业务写;B = term-3 在同一 index 的另一条写;N = term-4 的 no-op。

(a) S1 宕机前(只复制到 S1、S2)

节点 idx1 idx2 idx3 备注
S1 1/1 2/2 (A) Leader,随即宕机
S2 1/1 2/2 (A) 已收到 A
S3 1/1
S4 1/1
S5 1/1

(b) S5 写完 2/3 后宕机

节点 idx1 idx2 idx3 备注
S1 1/1 2/2 (A) 仍 down
S2 1/1 2/2 (A)
S3 1/1 投过 S5
S4 1/1 投过 S5
S5 1/1 2/3 (B) term-3 Leader,随即宕机

(c) 错误:S1(term 4)把 2/2 复制到多数并立刻 commit

节点 idx1 idx2 idx3 备注
S1 1/1 2/2 (A) Leader;误把 idx2 标为 committed
S2 1/1 2/2 (A)
S3 1/1 2/2 (A) 刚被补齐,与 S1、S2 组成多数
S4 1/1
S5 1/1 2/3 (B) 稍后若当选,用 B 覆盖 A

此时客户端若已收到「A 成功」,随后 S5 以更「新」的 lastLogTerm=3 赢得选举并覆盖 idx2,已提交的 A 消失——Safety 破裂。

(d) 正确:先追加并 commit 当前 term 条目 3/4 (N)

节点 idx1 idx2 idx3 备注
S1 1/1 2/2 (A) 3/4 (N) 只对 3/4 计多数 commit
S2 1/1 2/2 (A) 3/4 (N)
S3 1/1 2/2 (A) 3/4 (N) 三份 3/4 → commit;A 间接提交
S4 1/1 (对齐中) (对齐中) 随后追上 Leader
S5 1/1 2/3 (B) 缺 3/4,对持有 3/4 的投票者而言更旧,无法再当选

自学检查:遮住上表,只看 §4.3 开头四句,能否在纸上复原 (a)→(d) 每一格?复原不了说明 Figure 8 还没进长期记忆。

这条规则与选举限制一起,堵住「先宣称提交、再被覆盖」的漏洞。

4.4 commitIndex 与应用

4.5 客户端重试与「至少一次」

网络超时后客户端重试同一写,Leader 可能已提交也可能未提交。Raft 本身保证的是日志位置上的命令一致,不自动提供「恰好一次业务语义」。常见工程配套:

若不做幂等,用户会把「Raft 很安全」误读成「业务不会双花」——前者是共识安全,后者是应用协议。

4.6 只读路径为何另开专题

未经协助的 Follower 本地读,可能读到:

因此「读」要么走 Leader,要么用 ReadIndex / 租约读等协议扩展。本篇不展开实现,见 raft-deep


五、安全不变量:为什么「读到的已提交数据」不会收回

本节给出四条性质与 Leader Completeness 的证明轮廓(非正式、无完整 TLA+)。形式化兴趣可参阅 Ongaro 论文附录与社区 TLA+ 规格。

5.1 四条性质

性质 含义 若破坏
Log Matching 同 index+term ⇒ 前缀全同 复制修复无法收敛
Election Restriction 选票只给日志足够新的候选人 落后节点当选并覆盖历史
Leader Completeness 已 commit 一条目必出现在所有更高 term 的 Leader 日志中 新 Leader 丢失旧提交
State Machine Safety 任意节点在 index \(i\) 应用的命令唯一 客户端看到矛盾状态

目标性质通常是 State Machine Safety;Raft 证明路线是先证 Leader Completeness,再由日志覆盖规则推出状态机一致。

5.2 Leader Completeness 证明轮廓(反证)

命题:若条目 \(e\) 在 term \(T\) 被 commit,则一切 term \(U>T\) 的 Leader 日志都包含 \(e\)

假设存在反例,取最小的违规 term \(U\),其 Leader \(L_U\) 不含 \(e\)

  1. \(L_U\) 当选时就不含 \(e\)(Leader 只追加不删自有前缀)。
  2. \(e\)\(T\) 被 commit ⇒ 存在多数派 \(Q_c\) 已存 \(e\)\(L_U\) 当选需要多数派 \(Q_v\)。存在节点 \(v \in Q_c \cap Q_v\)
  3. \(v\) 在投票给 \(L_U\) 前持有 \(e\)(中间各 Leader 若都含 \(e\),不会指示删除 \(e\))。
  4. 选举限制要求 \(L_U\) 的日志至少与 \(v\) 一样新。结合 Log Matching,可推出 \(L_U\) 也应含 \(e\)——矛盾。

故命题成立。Figure 8 的 commit 规则保证:被计入 commit 的「当前 term 条目」不会在上述推理里被后任合法覆盖。

5.3 从 Leader Completeness 到状态机安全

一条短链即可收束:

  1. 条目 \(e\) 在某 term 提交 ⇒ 一切后续 Leader 日志含 \(e\)(Leader Completeness)。
  2. Leader 日志为权威;Follower 经一致性检查与冲突截断,最终与 Leader 对齐(Log Matching)。
  3. 各节点仅按 commitIndex 顺序应用 ⇒ 同一 index 的应用命令唯一(State Machine Safety)。

Figure 8 的规则保证第 1 步的前提「\(e\) 真的算提交」不会被后任合法否定。

5.4 Safety 优先于 Liveness

永久多数派丢失(例如五节点剩两节点且无法组成多数)时,集群应停止提交新命令,而不是在少数派上冒充成功。这不是实现疏忽,而是 Safety 优先的后果。运维上的「强制提升少数派」属于危险干预,需人工接受可能的数据分叉——共识库默认不会替你做这个决定。

另一侧是分区愈合:旧 Leader 若仍以为自己是 Leader 并接受客户端写,这些写在少数派上不得被当成已提交;一旦它连上持有更高 term 的节点,必须下台并回滚其未提交后缀。客户端若在超时后重试到新 Leader,应依赖 §4.5 的幂等设计。


六、快照与成员变更(最小必要集)

6.1 快照(Snapshot)

日志不能无限增长。节点将状态机打成快照,记录 lastIncludedIndex / lastIncludedTerm,然后丢弃该 index 之前的日志。落后 Follower 可通过 InstallSnapshot(或等价流式传输)追上,而不必回放全部历史。

快照截断已应用的日志前缀

细节(分块传输、与 Apply 的并发、etcd 的 HTTP/gRPC 路径)见 raft-deep

6.2 联合共识(Joint Consensus)

成员变更若「先加后删」或「先删后加」步骤不当,可能出现两个不相交多数派同时以为自己合法。论文方案是 Joint Consensus:先进入同时满足旧配置 \(C_{\mathrm{old}}\) 与新配置 \(C_{\mathrm{new}}\) 多数派的过渡配置,再切换到纯 \(C_{\mathrm{new}}\)

flowchart LR
  Cold[Config_Cold]
  Joint[Joint_Cold_and_Cnew]
  Cnew[Config_Cnew]
  Cold --> Joint --> Cnew

单步成员变更与 etcd ConfChange V2 的工程简化见 deep 文;本篇只要求记住:变更期间的多数派定义本身也必须通过日志提交,不能「改完配置文件就重启当完成」。


七、工程补丁地图(只指路,不拆源码)

论文 18 页与生产库之间的差额,多半不是「改算法」而是补全故障与性能场景。下表一眼定位,细节全部链到深度篇。

主题 动机(一句话) 阅读
PreVote 分区节点恢复时避免搅乱健康集群选举 raft-deep §2
ReadIndex / LeaseRead 线性一致读少走完整日志往返 deep §5
LeaderTransfer 主动移交领导权做运维 deep §5
ConfChange V2 / Learner 多节点变更与冷启动副本不拖累 quorum deep §5
Pipeline / Batch / Async Apply 抬升稳态吞吐 deep §6
Multi-Raft 用多组 Raft 摊开 Leader 热点 deep §7;本文 §8.3

旧的精简入门版仍保留在 Raft:让共识算法不再是黑魔法;需要 etcd 库结构时优先读 deep,而不是更早的 raft-etcd 单篇。


八、研究讨论:Raft 之后还在吵什么

本节按 WRITING_GUIDE 第十四节组织:谱系 → 分叉 → 假设与工程间隙 → 开放问题。不宣告「已被某路线统一」。

8.1 奠基谱系

工作 出处 在本文中的角色
Fischer et al., FLP JACM 1985 Safety/Liveness 不可能同时在纯异步下兼得
Lamport, Paxos Made Simple 2001 单命令共识叙述;Multi-Paxos 规范不完整是 Raft 动机之一
Ongaro & Ousterhout, Raft USENIX ATC 2014 可理解性优先的完整复制日志协议
Ongaro, PhD thesis Stanford 2014 PreVote 等扩展的原始出处
Howard et al., Flexible Paxos OPODIS 2016 选举/复制仲裁只需相交,不必同为多数

Ongaro 在论文中做了受控的学生理解实验:同等测试下 Raft 得分与自评理解高于 Paxos——这支撑的是可理解性主张,不是「Raft 渐近更快」。

8.2 Flexible Quorum:稳态延迟 vs 选举代价

Flexible Paxos 指出:准备阶段(选举/Prepare)与接受阶段(复制/Accept)的仲裁集只需两两相交,不必都取 \(|\mathit{majority}|\)。例子:\(N=5\) 时可取选举仲裁 \(4\)、提交仲裁 \(2\),使稳态写只等更小集合,但选举更难达成。

经典多数与柔性仲裁的对照

交集推演:\(N=5\),选举 \(4\),提交 \(2\)

记节点全集 \(S=\{S_1,\ldots,S_5\}\)。经典 Raft 取

\[ |Q_{\mathrm{elec}}| = |Q_{\mathrm{commit}}| = 3 \]

任意两个大小为 3 的子集必交,故「存过已提交条目的多数派」与「选出新 Leader 的多数派」共享至少一名见证者。

Flexible 配置改为:

\[ |Q_{\mathrm{commit}}| = 2,\qquad |Q_{\mathrm{elec}}| = 4 \]

(一般规则:只要任意合法 \(Q_{\mathrm{commit}}\) 与任意合法 \(Q_{\mathrm{elec}}\) 相交即可;一组充分条件是 \(|Q_{\mathrm{commit}}| + |Q_{\mathrm{elec}}| > N\)。)

验证本例:\(2+4=6>5\)。任取提交仲裁 \(C\)\(|C|=2\))与选举仲裁 \(E\)\(|E|=4\)):若 \(C\cap E=\emptyset\),则 \(|C\cup E|=6>|S|\),不可能。故交集非空。

Safety 直觉不变:条目 \(e\)\(C\) 上持久化并按协议计为提交后,任何新 Leader 的选举集合 \(E\) 里至少有一名成员见过 \(e\)(再叠加入选限制与「只 commit 当前 term」等规则,完整表述见 Flexible Paxos 原文)。改的是代价

经典多数 本例柔性配置
稳态写 等 3 个应答 可只等 2 个 → 常绕过最慢副本
选主 凑齐 3 票 必须凑齐 4 票 → 容错与可用性变差
可容忍同时失联 2 节点(写与选都按 3) 写路径仍可在「2 个活着」时前进;选主时失联 2 个就可能凑不齐 4

因此柔性仲裁不是「免费加速」,而是把延迟从高频路径(写)挪到低频路径(选举)。成员变更时 \(N\) 与两套 quorum 必须一起重算,否则「以为相交」会在换人后失效——这是工程间隙的核心。

工程间隙:经典 Raft 实现与教材几乎都钉死多数派,心智模型简单;柔性仲裁要重写投票与提交计数、仔细处理成员变更,调试成本上升。

FlexiRaft(Yadav & Rahut, CIDR 2023,Meta 生产 MySQL 复制栈)把柔性仲裁相关思路落到大规模 MySQL 部署动机中:跨地域副本下,固定多数提交会把写延迟绑在慢区 RTT;文中把 data commit quorum 做成可配置,并由其自动推导 leader election quorum 以保持相交。读该文时应分清:哪些是对 Raft 的协议参数化,哪些是 MySQL / binlog server / 地域 group 的集成细节(B 级系统经验,不是新的通用定理)。

FDRaft 一类工作用延迟感知动态缩小 commit quorum(学位论文路径常见);引用其吞吐数字时必须标明实验环境与是否经 peer review,本文不转述未核对的倍率。

8.3 Multi-Raft:横向扩展而非改单组语义

单组 Raft 的 Leader 在 CPU、网卡与磁盘上形成热点。TiKV、CockroachDB 等采用 Multi-Raft:数据按区间(Region / Range)切开,每段一个独立 Raft 组,领导权散落在不同节点。

单组 Leader 瓶颈与多 Raft 组并行

边界:Multi-Raft 解决的是组内一致复制;跨区间原子事务需要上层协议(例如 Percolator 风格),不是「把 Raft 再调一次参数」就能消失。组内机制预修可先读 RocksDB 内核系列 与 raft-deep §7;HTAP / TiKV 分布式事务另题。

摊开 Leader 之后,运维重心往往变成:热点区间调度、Leader 分布是否均匀、迁移/分裂时的短暂不可写。单组 Raft 的「选主」问题,在 Multi-Raft 里变成「成千上万个小组的调度与抖动」——扩展了吞吐,也扩展了控制面复杂度。

8.4 并行提交路线:EPaxos 与连续日志之争

Raft 日志无空洞:index \(k+1\) 的提交依赖对前缀顺序的共识进展。Egalitarian Paxos(Moraru et al., SOSP 2013)允许无冲突命令并发提交,潜在降低多主延迟,但冲突处理与实现复杂度明显高于 Raft。

这是有文献的真实权衡,不是口号:

立场 主张 代价
Raft 派 规范完整、工业实现成熟、易推断故障 Leader 瓶颈;槽位串行
EPaxos / 并行派 多主、冲突少时延迟更低 依赖图、恢复路径难

更细对照与实测框架见 14-epaxos17

8.5 与「可理解性」目标的张力

Raft 论文把可理解性做成可测主张。十年后工业补丁(PreVote、流水线、异步 Apply、柔性仲裁)重新堆回复杂度。这不是否定论文,而是提醒阅读时分层:

该掌握什么 不该指望一次读完
论文核心 三角色、两 RPC、四不变量、Figure 8 性能数字
生产库 I/O 解耦、流控、运维 API 当作另一套共识数学
研究变体 改了哪条仲裁/日志假设 默认「已取代 Raft」

写配置中心、元数据服务:先保证论文核心实现正确。写跨洋多活存储:再阅读 Flexible / Multi-Raft / 上层事务,并单独做故障演练。

8.6 开放问题(截至 2026)

  1. 地理分布:跨区多数派写延迟是否主要通过柔性仲裁 / 层级复制消解,还是业务应接受「本区多写、跨区异步」的一致性降级?
  2. Leadership 负载:Multi-Raft 摊领导权后,调度、热点 Region、迁移是否变成新的运维核心?
  3. 成员变更可用性:联合共识正确,但频繁换人时可用性窗口如何量化?自动运维是否引入新的裂脑风险?
  4. 形式化与实现差:TLA+ / 机器证明覆盖论文核心后,PreVote、Pipeline、异步 Apply 组合是否仍有逃逸的边例?
  5. 与 BFT 的边界:互联网失控环境要不要上 HotStuff 类 BFT(见 16-hotstuff)?CFT Raft 的威胁模型是否被误用于敌对节点场景?

九、常见误解

  1. 「Raft 就是更好的 Paxos。」 Raft 在可理解性与协议完整度上针对工程落地;理论能力与 Multi-Paxos 同属 CFT 复制日志。速度数字取决于实现与负载,不能从论文标题推出。
  2. 「多数副本落盘 = 可以提交任意任期的条目。」 Figure 8 表明对旧任期条目直接按多数提交会破坏 Safety。
  3. 「选举超时越短越好。」 过短在抖动网络下触发无效选举,吞吐崩盘;须覆盖心跳 RTT 分布。
  4. 「Follower 可以本地服务任意线性一致读。」 默认不行;需要 ReadIndex / 租约等机制(deep 文),否则可能读到未提交或过时前缀。
  5. 「上了 Multi-Raft 就等于解决了分布式事务。」 只解决分片内复制;跨分片原子性另议。

十、三句话小结与阅读路径

  1. Raft 用强领导者 + 复制日志把共识拆成选举、复制与可证明的 Safety 规则;随机超时是活性的工程近似,不是数学上取消 FLP。
  2. 最难的一节往往是 Figure 8 的 commit 规则Leader Completeness:多数派交集 + 选举限制 + 「只 commit 当前 term」共同守住已提交历史。
  3. 近年争论集中在柔性仲裁、地理延迟、Multi-Raft 扩展与并行提交替代;选型时先固定威胁模型与一致性需求,再读实现补丁,而不是先抄参数。

推荐路径

  1. 本篇(机制与不变量)
  2. raft-deep(etcd / Multi-Raft 工程)
  3. 14-epaxos17-consensus-engineering(替代路线与权衡)
  4. 下方五步可视化练习(必做)

对照 raft.github.io 的五步练习

打开 The Secret Lives of Data — Raft(官方可视化)。每一步先自己预测屏幕上会发生什么,再点播放;对不上就回到本文对应小节。

操作 你应能指出 对读本文
1 停掉当前 Leader,观察选举 谁先超时?term 是否加一?多数票如何凑齐? §3.2–§3.3
2 故意让两名 Follower 超时接近(多次重开直到 split vote) 为何本轮无 Leader?下一轮随机超时如何打破对称? §3.1
3 向 Leader 提交一条写,观察日志格子 条目先出现在 Leader 哪一格?何时变「已提交」颜色/标记? §4.1
4 在复制未达多数前杀掉 Leader,再选主 未提交后缀是否被新 Leader 覆盖或抛弃?客户端若已超时该怎么办? §4.3、§4.5、§5.4
5 造出「旧 term 条目已在部分节点、新 Leader 上任」局面(多次故障) 新 Leader 是否先写入当前 term 条目(可视化中的空/心跳推进)再间接提交旧条目? §4.3 手填表 (d)

做完五步仍觉得 Figure 8 飘忽:回到 §4.3,用纸笔只依据规则重填 (a)→(d),不要看答案表。


参考资料

核心论文

  1. Ongaro, Diego & Ousterhout, John. In Search of an Understandable Consensus Algorithm. USENIX ATC 2014.
  2. Ongaro, Diego. Consensus: Bridging Theory and Practice. Stanford PhD Dissertation, 2014.
  3. Howard, Heidi; Malkhi, Dahlia; Spiegelman, Alexander. Flexible Paxos: Quorum Intersection Revisited. OPODIS 2016.
  4. Moraru, Iulian; Andersen, David G.; Kaminsky, Michael. There Is More Consensus in Egalitarian Parliaments. SOSP 2013(EPaxos)。
  5. Yadav, Ritwik & Rahut, Anirban. FlexiRaft: Flexible Quorums with Raft. CIDR 2023(系统经验文,B 级辅助)。
  6. Fischer, Michael J.; Lynch, Nancy A.; Paterson, Michael S. Impossibility of Distributed Consensus with One Faulty Process. JACM 1985.
  7. Lamport, Leslie. Paxos Made Simple. 2001.

规范 / 实现 / 站内

  1. raft.github.io — 论文与可视化入口。
  2. Raft 深度重写:论文到 etcd
  3. 共识工程权衡
  4. 精简入门版

返回 分布式系统百科 | 下一站:Raft 深度重写

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-13 · distributed

【分布式系统百科】Raft 深度重写:从论文的 18 页到 etcd 的 15000 行

Raft 论文 18 页就能读完,但 etcd/raft 用了 15000 行 Go 才把它变成能在生产环境跑的代码。这篇文章从论文的每一个核心机制出发,逐一拆解工程实现中论文没说的东西:PreVote、ReadIndex、LeaderTransfer、ConfChange V2、流水线复制、Async Apply,以及 TiKV 的 Multi-Raft 实践。最后做一次精确的 Paxos 对比,并坦诚讨论 Raft 的已知缺陷。

2026-04-01 · distributed

Raft:让共识算法不再是黑魔法

Paxos 被引用了几千次,能正确实现它的人不超过几十个。Raft 用可理解性换工程落地,它的 Leader Election、Log Replication 和 Safety 三板斧,撑起了 etcd、TiKV 和大半个云原生基础设施。

2026-04-13 · distributed

【分布式系统百科】共识问题的精确定义:Agreement、Validity、Termination

共识到底在解决什么问题?Agreement、Validity、Termination 三个性质的精确含义是什么?Safety 和 Liveness 的区分为什么如此关键?FLP 不可能定理对工程实践意味着什么?本文从形式化定义出发,逐步展开共识的变体、原子广播的等价性,以及状态机复制这个最重要的应用。


By .