连载中 13/20

Raft 深入:两条提交红线与一份不可能丢的日志

2026-07-01 · 4056 阅读 · 0 评论 · 0 赞

入门解决「怎么活」,深入解决「怎么不丢」

上一篇的选举与复制解决的是集群「活着」的问题;这一篇抠的是「活得不丢、不乱」。Raft 论文用五条安全性性质收束这件事,对做业务的人,真正需要内化的是两条提交红线和一套脑裂免疫逻辑。先看最容易想错的那条——「过半 ACK 就提交」其实是有条件的。

红线一:只提交当前任期的日志

直觉版本是「日志复制到过半就 commit」,但直接这么实现会丢数据。用一个经典时间线(Raft 论文 Figure 8 的故事)还原:

t1  S1 当 Leader(Term=2),写日志 e2.2,复制到 S2,但还没过半
t2  S1 掉线;S5 凭「日志不比自己新」的例外当选(Term=3)
    —— S5 没有 e2.2,但它的日志更新(Term 更高),合法
t3  S5 写自己的日志 e3.2,又掉线
t4  S1 回来重新当选(Term=4),继续把 e2.2 复制到过半(S1,S2,S3)
    ← 按直觉此刻 e2.2 已「过半」,但它属于旧任期 Term=2,仍不许提交
t5  若此刻允许提交 e2.2,然后 S1 再掉线、S5 当选(Term=5)
    S5 会用 e3.2 覆盖 e2.2 —— 一条「已提交」的数据就这么丢了

Raft 的红线因此写成:commitIndex 只能在当前任期的日志上推进;旧任期日志必须「搭车」——等当前任期有新日志提交时,一并提交。t4 的 S1 想提交 e2.2,得先写一条 Term=4 的新日志让它过半,借新日志的提交把 e2.2 一起抬过线。这条红线略显迂回,却换来一个铁一般的不变量:凡是宣称已提交的数据,任何未来 Leader 都无法覆盖

日志新旧的精确判定

选举纪律里「日志不比自己新就拒绝投票」,「新旧」的判定规则要一字不差:先比最后一条日志的 Term,Term 大者新;Term 相同再比日志索引,长(大)者新。两步比较杜绝了两个方向的漏洞:Term 大但日志短的不会被误判落后,索引长但 Term 旧的也冒充不了新——选举永远选出「见多识广」的那一位,数据落后者连提名资格都没有

「不可能丢」的数学直觉

把红线一、投票纪律、log matching 三块拼起来,可以得到一个不需要形式化证明的直觉:已提交意味着过半节点留了底稿;任何新 Leader 的当选也要过半投票;两个「过半」必有交集——交集里的节点既见过那条日志,又有投票权。而它只会投给「日志不比自己新」的候选人,于是新 Leader 必然见过那条已提交日志,当选后按 log matching 保留它。多数派交集 + 选举纪律,把「已提交数据不丢」从概率变成了数学。这正是第 7 篇 Redis 丢锁与 ZAB 共识的分水岭所在。

读请求与脑裂

写要走 quorum,读呢?一个 Leader 读写状态可能落后(它刚被罢免自己还不知道),直接读会违反线性一致。etcd 提供两个档位:ReadIndex——Leader 先向多数派确认「我还是现任」再读,不写日志、一次往返;Lease Read——Leader 靠心跳租约自信自己还在任,零往返直读,快但依赖心跳时序。锁场景里「我还有锁吗」这类判断走 ReadIndex 档位,比 ZK 的 sync 命令语义更精确。至于脑裂:少数派侧的旧 Leader 继续发号施令,但过半 ACK 凑不齐,一条日志都提交不了;多数派侧选出新 Leader 正常服务——分裂只冻结旧的一侧,不毒化新的一侧,分区恢复后旧 Leader 看到 Term 落后自动退位(第 9 篇 epoch 退位的同款剧情)。

机制作用护栏对象
只提交当前任期防止旧日志被新 Leader 覆盖已提交数据不丢
日志新旧判定落后者没有被选举权Leader 数据完整性
log matching日志强制连续无分叉副本一致性
ReadIndex / Lease读不违反线性一致读的正确性
多数派交集脑裂只冻结一侧分区安全

协议课到此结业。下一篇回到应用层,看 etcd 怎么用 Raft 的两个产物——租约(Lease)和全局 revision——把分布式锁做得比 ZK 更简洁:一个 lease 管生死,一个 revision 排公平。

503

10 年全栈工程师 · 503咖啡馆主理人

#Raft#提交规则#ReadIndex#Lease Read#脑裂#日志安全

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞