19 · 共识:已提交的决定如何跨故障保留
目标:解释多数派、任期和选主限制如何共同保护已经确认的决定。
主节点也需要被约束
单主可以给操作排序,却还没回答主节点故障后该听谁的。共识使多个节点对决定达成一致;复制日志把许多决定组成稳定序列。各节点以相同顺序执行确定性操作,就能得到相同状态。这是复制状态机的基本思路。
以 Raft 为例,任期标识一轮领导关系,每个节点每任期最多投一票;候选人还要满足日志新旧条件。多数派相交使两组选票有共同节点,但该节点必须持久记住投票、日志和任期。没有这些协议规则,相交只是集合论事实。
提交规则也不只是“随便一个旧条目有多数副本”:Raft 对用副本数直接推进提交的条目任期有约束。新 leader 要保留已经提交的历史,未提交的尾部则可能被覆盖。本课只演示日志新旧的投票条件,完整协议应阅读原文和使用成熟实现。
落后的候选人能获得多少支持
保存 consensus.py。元组是 (最后日志任期, 最后日志索引),按字典序比较,先比任期再比索引。它不是当前选举任期。所有节点在本轮尚未投票且可达,这是本例前提。
from itertools import combinations
logs = {"A": (3, 3), "B": (3, 3), "C": (3, 3), "D": (2, 2), "E": (2, 2)}
majority = len(logs) // 2 + 1
def eligible_votes(candidate):
return sum(logs[candidate] >= local for local in logs.values())
quorums = [set(q) for q in combinations(logs, majority)]
assert all(a & b for a in quorums for b in quorums)
assert eligible_votes("D") == 2
assert eligible_votes("A") == 5
assert eligible_votes("D") < majority
print("majority:", majority)
print("stale_candidate_votes:", eligible_votes("D"))
print("fresh_candidate_votes:", eligible_votes("A"))
uv run --python 3.12 --no-project consensus.py
预期输出:
majority: 3
stale_candidate_votes: 2
fresh_candidate_votes: 5
落后者只能获得两个落后节点的支持,不能被选为 leader。代码没有实现投票持久化、AppendEntries、成员变更或提交规则,因此 eligible_votes 仅表示满足这个条件的潜在票数,不能直接作为完整选举结果。
引导练习:① 假设 A、B 暂时不可达;② 只在 C、D、E 中计算可获得票数,法定多数仍为整个固定集群的 3;③ C 可获得 3 票,D 只有 2。不能把不可达节点从总成员数中自动删除,否则分区两侧可能各自宣称多数。
何时停止,何时继续
五节点集群在非拜占庭故障模型下通常可容忍两个节点不可用并在剩余多数可通信、稳定选主等条件下继续推进;不是任意两个故障都无条件及时完成。少数派应停止确认新写,安全性优先于无依据地继续推进。完全异步且允许故障的模型下,确定性共识无法无条件保证终止;实际协议通过时序条件、超时与重试获得进展。
共识日志中的读也要确认 leader 的有效性以及已应用的提交位置。单纯从自认为是 leader 的内存读取,可能读到过期数据。协调服务可用于成员发现、任务归属、锁或配置等少量关键决定;它不是所有业务读写的免费中央瓶颈。
独立练习:集群按 A/B 与 C/D/E 分区,旧 leader A 还活着。哪侧可以在正确协议下确认新写?旧 leader 恢复后如何处理?
参考推演
C/D/E 有可能选出符合日志条件的新 leader 并形成多数,A/B 不能形成 3 票,不能确认新写。恢复后旧 leader 观察更高任期并退位,按协议匹配日志;未提交尾部可以修正,已提交条目必须保留。如果上层把外部副作用交给旧 leader,仍需第 17 课的存储端防护与幂等,不因有共识就自动免疫。
若投票推演出现两个 leader,检查是否重复投票或偷偷改变成员分母。若日志条数更多却不应获胜,检查是否优先比较最后日志任期。在 design.md 写清楚生产复制由成熟数据库负责,模拟器只验证理解。
参考资料
- DDIA 第二版第 10 章:共识、复制日志与协调服务。
- Ongaro 与 Ousterhout:Raft 扩展论文,重点阅读第 5 节的选举、复制与安全规则。