08.01 系统模型与部分失败:一次超时究竟发生了什么
返回第八卷 · 事务与提交前置:06.07 · 崩溃恢复前置:06.09 · 业务案例前置:06.12 · 网络前置:04.04
08.01 系统模型与部分失败:一次超时究竟发生了什么
DeepTutor 八节初稿经技术与教学审阅后的静态课程。A、G、S、B、
m-9与所有时刻都是虚构纸上模型;没有运行 Go、IM 服务、故障注入、网络实验或站点,也不声称 OpenIM 实际按此拓扑部署。本章把 S3 的数据库提交当作未来教学情景;当前 S2200 accepted_in_memory的合同不改变。
一、一条消息跨过多少独立的东西?
在 06.12,u-a 向会话 c-a 发送稳定 ID m-9,教学数据库事务若已知提交,未来 S3 v2 可以提议答复 200 stored_in_teaching_db。现在把它放进多节点路径:A 是发起请求的客户端,G 是接入网关,S 是权威消息存储,B 是可能在线的目标设备。A→G、G→S、G→A 回答、G→B 通知各是一段可单独延迟或断开的通信。即使 G 与 S 都是“服务端”,它们不是同一个进程,也不能由 A 的一次超时推断两者共同故障。
A 客户端 ──请求──> G 网关 ──写请求──> S 权威存储
↑ │ │
└──HTTP 回答──────┘ └──提交/查询事实
└──通知尝试──> B 设备本章给三类词定边界:节点是可独立运行/故障的进程或机器;链路是两个节点间传消息的路径;请求是一次尝试,业务消息 ID 则标识希望存储的同一条消息。一次请求失败不等于业务消息不存在;同一个业务意图换新 ID 也可能变成两条消息。B 收到通知更不能由 S 已提交直接推出。
| 第一遍 | 第二遍 | 交付物 |
|---|---|---|
| 节点、链路、请求与业务身份;相同超时的不同真相 | 故障模型、安全/活性、取消与重试、故障证据 | 四条纸上轨迹、一张观察/状态表、一份有条件的业务承诺 |
先画单个请求能看到什么,再画系统里发生了什么。A 只接收到了回复、错误或期限到达;A 不能直接读取 G 与 S 的内存,也不能把自己没有收到回包当作 S 没有提交。MIT 分布式系统课程的主备服务实验把崩溃、暂时网络故障和分区作为不同情景,这是本章建模的依据之一。MIT 6.824 主备实验
二、同一个 100 ms 超时,背后可以有四种真相
固定 A 在 t=0 ms 发 m-9,本次尝试的客户端期限为 100 ms。下面四条互斥的纸上轨迹,A 在 t=100 都只看到“期限到达、没拿到确定回答”;这个观察不能反演出唯一真实状态。
| 轨迹 | G 与 S 可能发生了什么 | t=100 的权威结果 | A 看见 |
|---|---|---|---|
| R1 请求未达 G | A→G 请求在途中无声丢失 | 本次请求未导致 S 提交 | 超时 |
| R2 G 已收但排队/暂停 | G 尚未向 S 形成提交,之后也可能继续 | t=100 尚未提交;以后仍需查证 | 超时 |
| R3 S 已提交,回答丢失 | S 在 t=20 提交 m-9,G→A 回包未到 | m-9 已在 S 提交 | 超时 |
| R4 S 已提交,G 随后崩溃 | S 在 t=20 提交,G 在回 A 前崩溃 | m-9 已在 S 提交 | 超时 |
R2 的关键是时间点:t=100 尚未提交,不代表未来永远不会提交。G 可能从暂停中恢复,或者它到 S 的请求已经在途。R3/R4 则说明“A 没收到成功”不等于“S 未成功”。这也解释 06.09 的本机提交与 HTTP 回答分界,只是现在多了进程和链路。06.09 日志与崩溃恢复
纸上追加一个迟到响应:S t=20 已提交,G 的答复 t=120 才到;A 在 t=100 已停止等待。迟到答复或被客户端丢弃的答复,不会倒转 S 的提交。100 ms 是本次等待预算,不是网络最大延迟、服务器故障证明或事务撤销命令。
三、故障模型:崩溃、暂停、延迟和分区分别是什么
为了推理,先声明本题的非恶意故障模型:节点可能停止运行、暂时停顿或恢复;网络可能丢失、延迟或隔断消息,但节点不会故意伪造响应。所谓 crash-stop 是某个节点在本次运行中停止;如果它重启,可把它当作带有新内存状态/任期的下一次运行。暂停可能是调度、GC、锁等待或负载;从外部看,它与短期失联很像。分区是某些节点之间无法互通,另一些路径仍可能通。MIT 6.824 主备实验
例如 A 能连 G,G 却连不上 S;与此同时 B 或另一个 G2 可能连得上 S。这叫部分失败:系统的一部分能继续工作,另一部分只能等待或返回不确定状态。它不同于单机程序整体退出,也不是“网络全部坏了”。一条 TCP 连接确认了字节到达某层,不替 S 做事务提交,更不替 B 做应用阅读确认;04.04 已讲传输 ACK 与业务确认分层。
异步模型在本章只表示不预设一个各节点必然遵守的已知严格消息延迟或计算时长上界。于是等待 100 ms 后,你可以选择停止等待、怀疑故障、重试或查询,但不能从时长单独证明对方已死;一个慢节点与一个失联节点在这段观察里可能无法区分。后续 08.06 才讨论多数与共识。经典 FLP 论文针对完全异步、确定性共识且可有一个故障进程证明了保证终止的限制;它不是“任何 IM 查询都不能完成”的口号,本章只用它提醒读者写清假设。FLP 原论文
四、安全性与活性:先说“不坏”,再说“何时能前进”
安全性(safety)说坏事不发生。例如本教学 SQL 存储用 message_id 主键,使同一 ID 至多一条权威消息行;成员检查与退群在同一受控事务边界内,要求退群先完成时不再接受该成员发送。注意限定词:主键只能保证相同 ID不重复;A 若超时后换成新 ID,又发了同一业务内容,仍可能有两条语义重复消息。安全还取决于所有写入路径执行同一授权规则,并非一个索引包办。
活性(liveness)说在给定假设下最终能取得进展。例如“如果权威存储恢复可读、网络最终连通、授权仍允许查询,A 最终可按稳定 m-9 查明权威记录是否存在”。若网络永久分区或权威存储永久不可用,不能承诺在固定时间内一定完成该查询。若 S 已提交但 A 暂时查不到,还要排除查询副本滞后和请求仍在途,不能把一次空结果当终局判定。安全与活性要各给范围、前提和可观测证据。
| 拟写承诺 | 性质 | 需要补充的条件 |
|---|---|---|
同 message_id 不出现两条权威记录 | 安全 | 唯一键覆盖所有写入口;不同 ID 的语义重复另管 |
| 已退群者不被新提交路径放行 | 安全 | 成员资格和写入共享可控冲突边界 |
A 超时后最终知道 m-9 状态 | 活性 | 权威查询可恢复、网络连通、有权限与稳定身份 |
| B 最终收到每条消息 | 活性候选 | 必须另设计离线保留、重试、设备确认与期限 |
不要把“可用性”写成“所有请求在任何分区里都返回成功”:这可能要求系统在不知道权威状态时凭猜测回答。对于 m-9,如实返回未知、稍后由授权查询解决,也是一种业务可解释的行为。
五、Go 取消与重试:停止等待,不等于撤销远端事实
Go 的 context.Context 可在请求链上传递期限和取消信号,帮助处理函数及时停止不再需要的工作;它是协作式信号。G 收到取消时,S 可能已在 t=20 提交,或者 S 尚未处理取消。数据库驱动/网络操作如何响应取消也取决于具体执行时刻。因而 ctx.Err()==context.DeadlineExceeded 证明的是本地等待期限到了,不证明远端没有写入。Go Context 官方说明 · Go 数据库取消文档
当前 09.02 S2 合同 对重复 ID 一律返回 409,即使正文相同;未来 S3 v2 只提议把成功点改为数据库提交,不自动更改重复响应。A 超时后不要换新 ID 盲发;沿可信身份向权威数据源查 m-9,核对会话、发送者及受控意图。若随后重试得到 409,所知只是“该 ID 已被占用”,并不能仅凭状态码证明原请求成功。若查询返回“未找到”,也要考虑 R2 的在途写入和读取来源;需要有明确定义的终止/幂等协议,后续 07.07–07.10 才深入。
A 的本地状态:等待 → 超时/未知 → 授权查权威 → 已确认存在 / 明确失败 / 仍未知
S 的可能状态:未收到 → 在途/处理中 → 已提交这两行不是同一状态机,不能把 A 的“超时”映射成 S 的“未收到”。若系统希望让同请求重试返回原结果而非 409,需要另行审查并版本化接口合同;本章保留现有语义。
六、健康检查与旧节点恢复:怀疑不能直接升级为事实
网关 G 连续几次健康检查无响应,只能说明观察者在这些时刻未收到预期答复。G 可能崩溃、暂停、网络隔离,或检测器本身过载。换路由可以改善可用性,但不能据此证明旧 G 已停止处理旧请求;如果旧 G 恢复并继续把过期写请求送给 S,需要依靠业务键、权威节点和后续代次/围栏规则防止重复或越权。08.06–08.07 将讲多数、任期、租约和 fencing;本章先列出旧节点仍在工作这一反例,不提前给出未审阅的实现协议。MIT 6.824 调试指导
观测记录应能用 message_id=m-9、可信主体、会话、请求/追踪 ID、每跳进入/离开与 S 提交阶段串起证据,同时按 09.08 脱敏,不能把正文、凭据或私有会话详情当调试便利随意写日志。A 的 timeout 指标只统计客户端期限结果;数据库已提交、B 通知尝试、设备已读有各自的分母和测量点,11.01–11.03 已建立这套口径。
七、给故障注入写预测表,再决定怎样观察
下表是学习者未来隔离环境的测试设计,本课程没有真正断链或运行服务。每条轨迹先定义触发点、权威状态和 A 的观察,再列可核对证据;用门闩/受控代理把阶段固定,比依赖 Sleep 猜竞态更可重复。
| 注入位置 | A 预计观察 | S 可能事实 | 需要的证据 |
|---|---|---|---|
| A→G 前丢请求 | 超时/连接错误 | 未因本次请求提交 | G 入站记录、S 权威查询 |
| G 已收、G→S 暂停 | 超时 | t=100 尚未提交;恢复后可能提交 | G 队列/在途、S 最终查询 |
| S 提交后丢 G→A 回包 | 超时 | m-9 已提交 | S 提交/查询、A 收包记录 |
| S 提交后杀 G | 超时 | m-9 已提交 | S 与 G 的时序、重启后权威查询 |
| S 可用但 G→S 分区 | 超时/明确依赖失败 | 该 G 未必能提交;其他 G 可能可达 | 每跳网络与权威进度 |
一次实验还要记录统一时钟口径、请求 ID、注入开关和故障解除时刻;t=20、t=100 仅是本章理想模型,不应拿多机壁钟直接当绝对事件顺序。关注未知结果比例、恢复后查证完成时间、重复/越权是否出现,再连到业务 P95/P99。没有 S 的权威状态证据,只看 G 日志和 A 报错无法证明 R1 与 R3 的区别。
八、完成第一张分布式故障说明书
交付四件静态材料:A/G/S/B 节点与链路图、R1–R4 的四条时间线、每条安全/活性承诺的前提、故障注入预测与证据矩阵。读者要能指出“同一个 A 超时可对应不同 S 状态”,且能按现有 409 合同处理稳定 ID,而不是把 context 取消当数据库回滚。
分层练习与反馈
1–8 认对象和观察,9–16 推演故障,17–22 评审业务保证与证据。先写预测,再展开答案。
1. A、G、S、B 分别代表什么?
A 是发送客户端,G 是接入网关,S 是权威消息存储,B 是可能在线的目标设备。
2. A→G 通了,就证明 G→S 也通吗?
不能。链路可独立失败,部分失败的核心就是一些路径可用、另一些不可用。
3. `m-9` 与“这次 HTTP 请求”是同一个身份吗?
不是。m-9 是希望存储的业务消息身份,一次或多次网络尝试可围绕它发生。
4. 当前 S2 的 200 表示 S 数据库已提交吗?
不表示。现有 S2 只是 accepted_in_memory;S3 stored_in_teaching_db 是未来纸上提议。
5. A 在 100 ms 期限到达,能证明 G 死了吗?
不能。G 可能暂停、排队,回包可能丢失或仅迟到。
6. 崩溃与暂停在本题怎样区分?
崩溃指进程在该运行中停止;暂停指暂时不前进但可能恢复。短时外部无响应不一定能区分它们。
7. 网络分区等于全部机器都坏了吗?
不是。可只有 G→S 不通,其他客户端或网关仍能访问 S。
8. TCP ACK 能证明 B 已读 `m-9` 吗?
不能。传输字节确认、S 提交、B 应用收到和用户阅读是不同层。
9. R1 请求未达 G,t=100 的 S 状态是什么?
本次请求没有使 S 提交;A 仍应按可观察到的连接/错误证据分类。
10. R2 t=100 尚未提交,能保证 t=120 仍不会提交吗?
不能。G 可能从暂停恢复或请求仍在途,最终状态仍需查证。
11. R3 与 R4 对 A 的观察一样吗?对 S 的事实呢?
A 都可能只见超时;S 在两条轨迹中都已提交。R4 多了 G 崩溃。
12. S 在 t=20 已提交、A 在 t=100 超时,A 能直接换新 ID 重发吗?
不能。换 ID 可能产生第二条业务消息;应保留稳定 ID 并授权查询权威状态。
13. Go `context` 取消会自动撤销 S 已提交事务吗?
不会。取消是协作信号,不能倒转已发生的远端提交。
14. 重试 `m-9` 返回 409,已证明首次请求是同一意图吗?
没有。只证明 ID 已占用,还须核对会话、发送者和原始意图。
15. “同 ID 至多一条权威行”属于什么性质?
安全性:违反时就是坏事已发生。不同 ID 的语义重复仍需其他规则。
16. “网络最终恢复后 A 能查明状态”属于什么性质?
活性,但依赖权威可读、网络连通、授权有效等前提,不能无条件保证固定时限。
17. 永久分区下能承诺所有 A 请求在 100 ms 内完成吗?
不能。缺少可达权威和已知延迟上界时,应有明确超时/未知行为。
18. 健康检查连败三次能证明旧 G 物理死亡吗?
不能。可能只是暂停、网络隔离或检测器过载;需要防旧节点迟到写的后续机制。
19. 为什么 `m-9` 的服务日志要记录阶段,又不能记完整正文?
阶段/关联 ID 帮助区分 R1–R4;私有正文和凭据可能泄漏,应按脱敏规则限制。
20. A 的 timeout 率能直接代表 S 未提交率吗?
不能。R3/R4 使 A 超时但 S 已提交;两个指标分母和事件不同。
21. 设计 R3 测试时,为什么要在 S 提交后受控丢回包?
这样才能固定“权威已提交、A 未知”的轨迹并核对查证流程;随意 Sleep 不保证事件顺序。
22. FLP 论文是否证明本题所有 IM 历史查询永远不能成功?
没有。它讨论特定完全异步故障模型中的确定性共识终止限制,不是对单次普通查询成功与否的结论。
本章完成标准与下一步
能不看答案画出 A/G/S/B 路径,对同一 100 ms 超时列出至少四条不同真实轨迹,并为“同 ID 不重复”“最终可查证”分别写出范围和条件,才算完成第一轮。第二轮由学习者在隔离环境记录可控故障与真实响应;本章没有替代实验。
按学习路线,下一章08.02 时间与顺序将建立物理/单调时钟和事件因果关系,08.03–08.04 再讲复制与读取一致性;具备这四章前置后进入第七卷的缓存和消息课程。