状态机复制需要共同认定的决策顺序,不只是多份“最新字节”。

学习目标

解释日志复制、选举与 Quorum 相交,预测三投票节点的行为,检查真实崩溃与暂停记录。

前置:一致性约定和本地持久化文件。

原理:同一个顺序,确定性地执行

副本从相同状态出发,认定同一份有序命令日志,再确定性执行命令。对顺序达成一致,才让状态相同。时间、随机数、外部调用等不确定因素必须在设计中被消除或显式记录。

Raft 把选主、日志复制和安全规则分开。Term 标识选举时期;每个投票者在每个 Term 最多投一票,候选者的日志还必须足够新。Leader 复制日志,并依协议的当前 Term 规则推进提交。尤其跨 Term 时,“某条记录在两块盘上”不是完整的 Raft 提交定义。

                 客户端
                   │
               leader n1
              ╱         ╲
         voter n2     voter n3
N = 3,多数派 = 2。任意两个多数派必然相交。
相交 + 投票/日志规则,保护已提交决策。

相交保证两项相互冲突的决策不能由完全分离的多数派分别证明;日志与投票规则让这个交点发挥作用。三个投票者中两个可达时,在有利调度下可以选举并提交;只剩一个就无法组成多数派。选举超时帮助系统推进,不证明旧 Leader 已经物理死亡。

共识与原子提交解决不同问题

Raft 为一个复制组决定日志顺序。两阶段提交协调多个事务参与者是否共同提交。2PC 中已准备的参与者可能等待协调者决策;用复制服务提高协调者决策的持久性,也不意味着两个协议可以互换。本实验只有一个 etcd 共识组,不实现跨分片事务或 2PC。

真实实验 A:先失去 Leader,再失去多数派

  1. 写入一个收到成功确认的值,用维护状态接口确定 Leader。
  2. 仅对这个自己创建的进程发送 SIGKILL。等待其他 Leader,读取旧值,再完成一笔新写。
  3. 用原来的数据目录重启该节点,检查它能读到两次写。
  4. 用 SIGSTOP 暂停一个 Follower,向可达节点写入;剩下两个投票者仍可推进。
  5. 恢复后再暂停两个 Follower,等待 1.4 秒,以 700 ms 截止时间发起写与默认线性一致读。记录未知结果,恢复节点后核对那笔写。

安装后执行 python3 scripts/run_all.py --repeats 3。首版每次重复都会执行三个实验家族。查看全部保存结果,包括超时写在恢复后的值。“700 ms 内未获成功”才是测量事实,不是普遍的延迟上界。

范围:同一主机上的真实 etcd 进程,各有独立 WAL 目录。暂停使投票者不响应;它不是非对称网络丢包实验,不是磁盘丢失测试,也不能证明多机性能。

自测

为什么不让唯一可达节点选出新 Leader?

它拿不到多数票。让每个隔离部分都能决策,会破坏相交论证,允许不兼容的决定。

实验能证明任何已提交写永远不丢吗?

不能,它只检查特定故障下的指定已确认值。普遍的安全保证来自协议与实现假设;运行提供有限范围的实现证据。

原始资料