在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

从消息到分布式共识

客户端超时,也可能发生在写入成功之后。三节点 Raft 服务中,领导者获得两份持久副本的证据,就能提交并应用当前任期命令,即使第三台仍落后。之后响应路径失败,客户端便无法确认成功。字节送达、持久化、提交、应用、收到结果是不同事件。

一张收据只证明它对应的阶段:送达不等于存档,存档不等于按协议获准执行,获准后通知也可能没送到。不能把每种确认都解释为整个请求完成。

副本落盘与领导者获知分开

客户端 C 发送请求 m42,要求 set x=7。S1 已是三节点集群的领导者,S2、S3 为跟随者。三台初始日志都到索引 2,已应用该前缀,x=0。

请求使用已建立的 TCP。TCP ACK 确认字节接收,不证明应用已解析或写盘。在该停顿点,全部持久日志仍到 2。TCP 是应用协议之下的可靠字节流,见 RFC 9293。

S1 接受命令,在当前任期 7 的索引 3 保存 3/t7;3 是位置,7 是选举任期,不是服务器编号或秒数。AppendEntries 把该项及匹配前缀 2/t6 发给 S2,S2 持久化后才应答。

此时两个磁盘已有副本,S1 却只知道自己这一份。回复到达后才能计入 S2。对于当前任期条目,已知两份持久副本达到多数,S1 可把 commitIndex 推到 3,再按日志顺序应用,将 lastApplied 推到 3,x 变为 7。持久日志、提交、应用各有状态,见 Raft 论文图 2 与 §5.3。

本服务在领导者应用后响应成功。S2 即使已有 3/t7,commitIndex 仍可暂为 2,需后续心跳带来新提交边界,才在本地提交、应用。响应不必等待所有跟随者应用,参看 Raft Apply 生命周期。

消息到共识逐步演示

默认响应丢失,值为 7,S3 全程延迟。

  1. C 发送 m42,S1 的 TCP 栈接收字节并回 ACK。客户端只获得传输收据,所有持久日志仍到 2。
  2. S1 解析命令并保存 3/t7,已知副本 1/3。commitIndex=2、lastApplied=2、x=0 不变。
  3. AppendEntries 携带 3/t7、前缀 2/t6 和旧提交边界 2,S2 保存。两份已落盘,但 S1 尚只知道一份。
  4. S2 的 AppendEntries OK 到达,S1 知道 {S1, S2} 已持久化,达到两台门槛。条目任期等于当前领导者任期,S3 无需参与。
  5. S1 先把 commitIndex 设为 3,应用状态仍 x=0;下一节拍才把 lastApplied 设为 3 并写 x=7。
  6. S1 生成 m42 成功结果,但客户端连接在交付前不可用,并持续到超时期限。C 超时,结果未知;S1 保留提交及 x=7。
  7. 与客户端期限独立地,S1 发 leaderCommit=3 心跳,S2 先更新 commitIndex,再更新 lastApplied 和 x=7。S3 仍为旧前缀和 x=0。
  8. 最终并列显示客户端的不确定,与服务已提交、已应用的事实。客户端缺少能确认成功的应用响应。

七项结果链记录阶段产物:存储条目用于复制,多数证据允许提交,已提交条目可供应用,最后一项必须有结果实际到达客户端。末次交接失败不会抹掉之前已完成的步骤。

超时为何意味着结果未知

保持值 7,只改场景:

场景本轮最终可观察服务状态客户端证据
正常响应S1、S2 存储并应用索引 3,S3 落后收到成功,x=7
响应丢失服务状态历史与正常响应相同收到 TCP ACK 后超时,应用结果未知
无多数只有 S1 存索引 3,应用都停在 2、x=0收到 TCP ACK 后超时,应用结果未知

无多数场景中,S2 的复制路径也不可用,S1 无法取得第二份持久副本,最终只有未提交条目。观察者能看见这个状态,客户端只知道没等到响应;而响应丢失场景同样超时,命令却已执行。

超时属于调用者的等待规则,不是服务端回滚指令。未提交条目日后可能提交,也可能在恢复中被替换,本课不预设它的未来。

重试需要应用自己的契约。这里 set x=7 是赋值,若改成 increment x,第一次执行后丢响应,再提交一个新日志项可能执行两次。关联 ID 本身不等于去重。Raft 排序日志,服务要抑制重复请求还需请求身份与结果跟踪,见 Raft 论文 §8。调用方应保留“结果未知”,按 API 的状态查询或幂等重试契约处理,共识不会自动把新提交等同于旧操作。

边界情况

  • 输入 0 时,应用 set x=0 不改变可见值,但 lastApplied 仍到 3,命令确实处理过。
  • S3 在全部场景停于 2。多数进展不要求同时应用;落后的日志前缀与同索引应用冲突命令不同。
  • S2 回执在途时,两个日志已有 3/t7,S1 证据仍是一份,不能使用尚未收到的信息。
  • 直接多数提交只适用于当前领导者任期创建的条目。旧任期条目还有额外规则,不能删掉该条件照搬。
  • 响应场景让连接持续不可用直至期限,不是把一次 TCP 分段丢包当永久丢失;普通丢包通常会重传。
  • 输入为 −99 到 99 的整数,是标签显示范围,不是 Raft 限制。

常见错误

  • 混用确认含义:TCP ACK 证字节接收,AppendEntries OK 证跟随者持久保存匹配项,应用响应才向客户端确认服务结果。
  • 把客户端算成副本。多数只在 S1、S2、S3 中计算,C 的传输确认没有日志副本。
  • 本地追加一次就报告成功。无多数场景正是已落盘但未提交。
  • 有日志就立即应用。S2 必须等获知提交边界。
  • 所有服务器同时变完成。每台独立获知并应用,后续通知含第一次复制 RPC 尚未带来的提交信息。
  • 把超时解释为未执行。响应丢失时 S1 的 lastApplied=3,没收到回复不会撤销执行。

模型范围

本课固定三个非拜占庭服务器、已选举领导者、相同初始日志和一次当前任期写入。连接建立和 TCP 恢复合并展示;省略选举、常规心跳、持久化延迟、批量、乱序、换主、旧任期提交、读、客户端重试去重、快照、成员变化。消息逐个安排,回放秒数不是网络测量。响应策略等待领导者应用,其他 API 可定义不同完成条件。继续看 Raft 共识 的选举与日志修复,或 TCP 握手 的连接机制。