本卷要解决的问题
卷三接着卷二的那句话往下问:当一次下单要跨进程、跨库、跨机房完成时,怎样保证它“要么都发生,要么能说清哪里没发生”。 卷二把延迟、容量、过载和变更治理讲完了,但那些结论都建立在一个隐含前提上:请求落在一个进程、一份数据、一个时钟里。卷三把这个前提拆掉,重新审视订单系统。
具体拆成四个子问题:
- 部分失败:调用超时之后,对方到底做没做?结果是成功、失败,还是未知?
- 顺序:没有共享时钟,两个事件谁先谁后?并发修改怎样被识别出来?
- 归属:同一份数据放在多个副本、切成多个分片之后,读写应该落在哪里?
- 收敛:已经产生的差异,靠什么发现、靠什么修复、修复到什么程度算结束?
卷一解决“边界画在哪”,卷二解决“边界内的代价怎么付”,卷三解决“边界被跨过去之后还剩什么保证”,卷四处理演进与治理。本卷不重复讲限界上下文、端口适配器,也不重讲缓存、限流和发布;需要时直接回查卷二。
全书结构:13 章分四段
13 章按“先建立模型、再处理副本与分区、然后解决跨库交付、最后协调与收口”分成四段。四段之下再按主题分六个块:基础与模型(1–2)、复制与共识(3–4)、分片与一致性(5–6)、事务与可靠交付(7–9)、协调与容灾(10–12)、综合(13)。
| 段 | 主题块 | 章节 | 回答的问题 | 本段产出 |
|---|---|---|---|---|
| 一、基础与模型 | 分布式基础、时间与顺序 | 第 1–2 章 | 哪些问题真的变了?谁先谁后? | 故障分类表、双节点模拟器、HLC 与版本向量 |
| 二、复制与分区 | 复制与共识、分片与一致性 | 第 3–6 章 | 多副本怎样达成一致?数据怎样切开? | 复制位点模型、迷你 Raft、分片迁移、一致性模型判定表 |
| 三、事务与可靠交付 | 分布式事务、Outbox、幂等与对账 | 第 7–9 章 | 跨库写怎样不半成功?重复怎样收敛? | 2PC/Saga/TCC、outbox 与去重、对账闭环 |
| 四、协调、容灾与综合 | ID 与锁、调度、多活、综合实验 | 第 10–13 章 | 谁执行?坏了怎么切?整套怎么验收? | 租约与 fencing、调度器、切换演练、跨库一致性验证 |
13 章不是 13 个中间件的介绍。每一章都往 arch-lab 里加一层可运行或可检查的产物;第 13 章把这些产物装进同一次改造,并用故障注入验收。只读结论、不跑代码,会漏掉分布式系统最要命的部分:那些“看起来对、只在切换和重试时才错”的路径。
章节依赖图
第 1 章 分布式基础(部分失败 / 故障模型 / 端到端)
│
└──► 第 2 章 时间与顺序(物理时钟 / 逻辑时钟 / HLC)
│
├──► 第 3 章 复制(单主 / 多主 / 切换窗口)
│ │
│ └──► 第 4 章 共识(Raft / 成员变更 / 线性一致读)
│
├──► 第 5 章 分区(分片键 / 再平衡 / 路由与元数据)
│ │
│ └──► 第 6 章 一致性模型(模型 / 会话保证 / 业务不变量)
│
└──► 第 7–9 章 事务与可靠交付(2PC / Saga / TCC / Outbox / 幂等 / 对账)
│
├──► 第 10 章 ID 与锁(Snowflake / 租约 / fencing)
│
├──► 第 11 章 调度(租约 / 任务分片 / 延迟任务)
│
└──► 第 12 章 多活与容灾(单元化 / 双向复制 / 切换演练)
│
└──► 第 13 章 综合(分片迁移 / 跨库验证 / 交接卷四)
这张图表达“先有什么再有什么”的阅读顺序,不是代码依赖。第 3 章与第 5 章可以互换:一个讲副本,一个讲切分。第 4 章必须排在第 3 章之后,第 6 章最好在第 2、5 章之后。第 7–9 章依赖第 6 章的不变量定义;第 10、11 章依赖第 7–9 章的幂等与交付语义;第 12 章需要第 3、4、5 章的结论;第 13 章要求前十二章的组件都已就位。
分章篇目与十三条速览
下面按章列出全部 39 篇正文。每章先给两三句话的定位和产出,再给三节链接。
第 1 章 分布式基础
同一段下单代码放进两个进程之后,失败不再只有“成功”和“异常”,还多了一种“结果未知”。本章先完成这个视角转换,再把崩溃、丢包、分区和拜占庭写成可注入的确定性网络,最后用远程调用的八个假设说明可靠性为什么必须端到端设计。
产出:双节点模拟器、故障分类表、一份重试放大实验记录。
第 2 章 时间与顺序
订单事件的先后不能靠机器时间。本章区分墙上时钟与单调时钟,解释 NTP 校正和回拨怎样制造“最后写入获胜”的数据丢失;再引入 Lamport 时钟、向量时钟和 HLC,把因果关系编码进事件本身,并在 arch-lab 的事件流里落地版本向量。
产出:时钟偏移实验、向量时钟实现、订单事件的 HLC 编码与并发检测测试。
第 3 章 复制
复制是把同一份日志放到多个节点,但“写成功”与“读得到”之间隔着位点。本章从单主复制的复制日志、提交位点与应用位点讲起,比较多主与无主复制的冲突合并,最后计算异步复制下的故障切换丢失窗口与 RPO。
产出:复制日志与位点模型、会话令牌读己之写、切换检查表与丢失窗口算式。
第 4 章 共识
共识解决的是“多数派同意之后,之前答应的不能反悔”。本章先写 Raft 的安全性不变量和状态机骨架,再实现选主、日志复制与多数派提交,最后讨论成员变更、快照和线性一致读的边界。书里实现的是用于教学的迷你 Raft,不承诺生产级性能。
产出:可运行的迷你 Raft、分区与脑裂测试、ReadIndex 读路径说明。
第 5 章 分区与再平衡
数据变大之后,第一个问题不是“选哪个分片中间件”,而是“按什么键切、切完谁负责”。本章比较分片键的业务约束与热点,讲一致性哈希的虚拟节点,再实现可重入的迁移、双写与路由表版本,最后把元数据传播延迟折算成扩容窗口的错误预算。
产出:分片与热点分析、一致性哈希分布测试、迁移状态机与路由回滚方案。
第 6 章 一致性模型
一致性模型不是越高越好,而是“业务不变量需要哪一档”。本章用历史记录检查器区分线性一致、顺序一致与因果一致,再讲读己之写、单调读和一致前缀的会话实现,最后把库存不超卖、状态单向推进、支付不重复扣款翻译成可检查的不变量。
产出:一致性模型判定表、会话保证测试、订单系统的不变量到模型映射。
第 7 章 分布式事务
跨库写入没有单机事务的“一起成功或一起失败”。本章拆解 2PC 的准备与提交、协调者故障导致的阻塞,再讲 Saga 的补偿顺序、语义锁和不可补偿步骤,最后比较 TCC 与本地消息表如何让中间状态对下游可见。
产出:2PC 参与者日志与恢复、编排式 Saga、TCC 空回滚与悬挂测试。
第 8 章 可靠消息与 Outbox
“把消息发出去”与“业务数据和消息一起生效”是两件事。本章用同库同事务的 outbox 解决前者,用 relay 位点与重复投递说明至少一次的真实含义;再讲消费端去重表、effect-once 的边界,以及顺序、重放和死信如何接入对账闭环。
产出:outbox 表与 relay、去重表、重放与死信处置流程。
第 9 章 幂等与对账
幂等键决定重复请求能不能被认出来,对账决定认不出来的差异最后怎么收敛。本章先定幂等键的作用域、生命周期与存储,再比较 T+1 全量与实时对账的差异分类,最后讨论冲正、补偿与资金类操作的最终一致。
产出:幂等键设计与并发测试、对账差异分类表、冲正任务与不变量检查。
第 10 章 分布式 ID 与锁
分布式 ID 和分布式锁常被当成“基础设施小事”,但它们直接决定唯一性与互斥是否成立。本章讲 Snowflake 的位分配与时钟回拨、号段模式的双缓冲,再讲租约锁、续约与 fencing token,最后说明锁失效后怎样用版本号和条件更新保住正确性。
产出:ID 生成器与回拨测试、带 fencing 的租约锁、锁失效下的幂等写入。
第 11 章 分布式调度
调度器要回答三个问题:谁执行、执行到哪、错过怎么办。本章比较轮询、数据库租约与领导者选举,再讲任务分片、检查点与幂等重跑,最后用时间轮和持久化延迟任务处理 misfire 与补偿上限。
产出:租约调度器、分片任务检查点、延迟任务与 misfire 补偿策略。
第 12 章 多活与容灾
多活不是“两个机房都部署”,而是“一个单元坏了,影响范围有多大”。本章比较单元化、同城双活与异地多活的隔离边界,处理双向复制的回环、归属与冲突,最后给出 RTO/RPO 测算、切换决策、只读降级与回切顺序。
产出:多活拓扑与故障域图、双向复制冲突规则、切换演练脚本与验收表。
第 13 章 综合实验
最后三节把前面的机制装进同一次改造。先从单库订单迁移到按用户分片,处理路由、跨分片查询、全局 ID 与双写;再用 outbox 加 Saga 完成一次跨库下单,注入重复、超时与崩溃验证不变量和对账收敛;最后整理卷三仍未证明的假设,交给卷四。
产出:分片迁移方案与回滚条件、跨库下单一致性报告、卷四治理问题清单。
前置与附录
本卷共 45 篇:1 篇序、1 篇前言、1 篇目录、39 篇正文、3 篇附录。前置材料给立场与用法,附录用于查表和验收。
| 篇目 | 作用 | 什么时候读 |
|---|---|---|
| 序 | 三个失败场景、卷二交接的六个未证明假设、四个立场 | 第一次打开本卷时 |
| 前言 | 结构、arch-lab 组件、L1–L4 分级、固定场景 S1–S3、数字口径 | 读正文前 |
| 目录 | 本篇,查章节、依赖与阅读路径 | 随时回查 |
| 附录 A 一致性模型与故障语义速查 | 模型判据、故障语义、CAP/PACELC 的正确表述 | 读第 2、6 章时对照 |
| 附录 B Go/Java 分布式组件对照 | 调度、锁、时钟、并发容器与库生态的结构对照 | 读第 3、10、11 章时对照 |
| 附录 C 分布式一致性验证清单 | 六类场景的注入手段、观测信号与上线前 20 条 | 第 13 章之后使用 |
三条阅读路径
路径 A:顺序通读
适合第一次系统补分布式与一致性、准备架构评审或面试的读者。按四段推进,不跳章。
| 阶段 | 章节 | 建议投入 | 读完应该能做什么 |
|---|---|---|---|
| 建立模型 | 第 1–2 章 | 5–6 小时 | 分类故障、写出可注入的失败场景、解释时钟回拨的后果 |
| 副本与分区 | 第 3–6 章 | 10–12 小时 | 设计复制位点、跑通迷你 Raft、完成一次分片迁移 |
| 事务与交付 | 第 7–9 章 | 9–11 小时 | 选型 2PC/Saga/TCC、实现 outbox 与去重、搭对账闭环 |
| 协调与容灾 | 第 10–12 章 | 7–9 小时 | 设计带 fencing 的租约、分片调度与多活切换 |
| 综合验收 | 第 13 章 | 4–5 小时 | 完成跨库下单验证并给出卷四问题清单 |
总计约 35–43 小时。代码量比卷二更集中在“状态机 + 消息传递”,建议至少完整跑通第 4 章的迷你 Raft 和第 8 章的 outbox,否则很难理解“至少一次”到底意味着什么。
路径 B:跨库改造驱动
适合手上正有一次“订单库拆出去、库存独立部署”任务的读者。按下面的顺序读,不要求先通读前两章。
- 1.1 哪些问题真的变了 与 1.3 八个假设
- 6.3 从一致性模型到业务不变量
- 13.1 从单库到分片
- 5.1 分片键与热点 与 5.2 再平衡
- 7.2 Saga 与 7.3 TCC 与本地消息表
- 8.1 Outbox 与 8.2 消费端去重
- 9.2 对账系统 与 9.3 冲正补偿
- 13.2 跨库下单的一致性验证 ,最后用附录 C 收敛检查项
第 1 步和第 2 步不能跳。先定义“哪些不一致是事故、哪些只是延迟”,后面的方案选择才有依据;否则很容易把所有读写都升级成强一致,付出不必要的代价。
路径 C:故障排查驱动
适合线上已经有具体症状的读者。先读 1.2 故障模型 ,建立“这次到底是丢包、分区还是重复”的判断语言,再查下面的症状表跳章。每跳一章,先看该章的“常见错误与边界”,通常比正文更接近现场。
症状到章节对照表
| 症状 | 先读 | 再读 |
|---|---|---|
| 主库切换后订单状态“倒退” | 3.3 切换与丢失窗口 | 3.1 位点与读己之写 |
| 跨库下单一半成功、一半悬挂 | 7.1 2PC 与协调者故障 | 7.2 Saga 与补偿 |
| 重复扣款、重复消费 | 8.2 消费端去重 | 9.1 幂等键设计 |
| 库存超卖、状态被并发改坏 | 6.3 业务不变量 | 10.3 锁失效后的正确性 |
| 扩容后请求打到错误分片 | 5.3 路由与元数据 | 5.2 迁移与双写 |
| 单个分片热点、CPU 打满 | 5.1 分片键与热点 | 5.2 再平衡 |
| 同一毫秒的事件排序错乱 | 2.1 物理时钟与漂移 | 2.3 HLC 与版本向量 |
| 双向复制互相覆盖 | 12.2 回环与归属 | 2.2 向量时钟 |
| 定时任务重复触发或空转 | 11.1 调度模型 | 11.2 分片与检查点 |
| 延迟任务漏触发、补偿过量 | 11.3 时间轮与 misfire | 11.1 调度归属 |
| 锁过期后两个 worker 同时写 | 10.2 租约与 fencing | 10.3 从互斥到幂等 |
| 选主反复抖动、提交变慢 | 4.1 Raft 角色与任期 | 4.2 选主与日志复制 |
| 对账差异修不完、越修越多 | 9.2 差异分类 | 9.3 冲正与补偿 |
| 切换演练不敢做、回切顺序不清 | 12.3 RTO/RPO 与演练 | 12.1 多活拓扑 |
arch-lab 在卷三扩展了什么
卷三沿用卷一的订单系统:Order、InventoryReservation、Payment 三个聚合,CREATED → INVENTORY_RESERVED → PAID → FULFILLED 状态机,分支 CANCELLED/REFUNDED。领域层不改,分布式能力通过平台端口接进来。
| 组 | 新增组件 | 目录 | 首次出现 |
|---|---|---|---|
| 时钟 | HLC、版本向量、可注入时钟 | internal/platform/clock | 第 2 章 |
| 复制 | 复制日志、提交位点、会话令牌 | internal/platform/replication | 第 3 章 |
| 共识 | 迷你 Raft、快照、ReadIndex | internal/platform/consensus | 第 4 章 |
| 分片 | 路由表、一致性哈希、迁移状态机 | internal/platform/sharding | 第 5 章 |
| 事务 | 2PC 参与者日志、Saga 编排器、TCC | internal/platform/tx | 第 7 章 |
| 消息 | outbox 表、relay、去重表、死信队列 | internal/platform/outbox | 第 8 章 |
| 对账 | 差异分类器、冲正任务、收敛检查 | internal/platform/reconcile | 第 9 章 |
| 协调 | ID 生成器、租约锁、fencing token | internal/platform/coord | 第 10 章 |
| 调度 | 租约调度器、任务检查点、时间轮 | internal/platform/schedule | 第 11 章 |
| 容灾 | 单元路由、复制监控、切换脚本 | internal/platform/dr | 第 12 章 |
代码仍分四级:L1 纯逻辑、L2 进程内端到端、L3 真实依赖、L4 多节点与故障注入。卷三的大部分章节是 L1/L2;第 3、4 章的复制与共识用确定性消息传递做 L2,不依赖真实网络;L3 只覆盖实际启动过 PostgreSQL 或 Redis 的部分;L4 只在第 13 章讨论场景与验收口径,不承诺完整的多节点实测。
领域层仍然不知道副本、分片和 outbox 的存在。平台组件通过端口注入,订单聚合只感知“操作可能失败、可能重复、可能延迟生效”。这是卷三反复强调的边界:分布式是基础设施的属性,不应该渗进业务状态机。
数字口径:实测、目标与示例
分布式系统的数字比性能数字更容易被误读,因为同一个结论可能依赖节点数、拓扑、故障注入方式和时钟条件。卷三统一用三种口径:
| 类型 | 写法 | 用途 |
|---|---|---|
| 实测值 | 附命令、机器、节点数、样本量与注入次数,数字直接来自正文的运行记录 | 证明某次运行的结果 |
| 目标值 | 写成 SLO 或设计约束,例如“切换 RPO 目标 0,RTO 目标 60 秒” | 设计约束,不是测量结果 |
| 示例值 | 用于算式或配置形状,例如“假设复制延迟 20ms、每秒 500 次写” | 说明计算过程 |
几条纪律:
- 写延迟必须同时写分位数、节点数和拓扑,单机数字不能外推成集群结论;
- 故障注入要写清注入了多少次、持续多久、是否可重放,不能只写“测过分区”;
- “共识写入耗时”没有命令和原始输出时,一律按示例值理解;
- 没有真正启动过的多节点环境,正文写“预期行为”,不写“实测”;
- 第 13 章的综合验证是场景验收,不等于生产容量或生产故障率;
- 本卷不写生产级 Raft,不伪造多节点压测,也不把中间件文档改写成章节。
六个常见误区
第一,把“分布式”等同于“拆服务、加机器”。拆开只改变了故障的传播路径,没有自动带来一致性。第 1 章先说明哪些问题真的变了,哪些只是变得更难观测。
第二,把 CAP 背成“三选二”。分区发生时只能在一致性与可用性之间取舍;没有分区时,延迟与一致性同样要取舍,这是 PACELC 补上的那一半。第 6 章和附录 A 会给正确表述。
第三,把“最终一致”当成“可以先不管”。最终一致需要收敛机制、收敛时限和差异可见性,三者缺一不可。第 9 章的对账就是为“最终”设定可验收的终点。
第四,以为有分布式锁就安全。锁会过期、会因主从切换丢失,持有者也可能在停顿后复活。第 10 章用 fencing token 和条件更新说明:正确性不能只押在锁上。
第五,以为用了消息队列就不会丢消息。投递保证是端到端的:生产端要 outbox,消费端要去重,中间还要处理重放与死信。第 8 章把这三段接成一个闭环。
第六,把重试当万能药。没有预算、退避和幂等的重试,会把一次超时放大成跨分片的重复写入。第 7、8、9 章分别从事务、消息和幂等三个角度处理这件事。
读完本卷的标准
不是“看完 45 篇”,而是能独立产出下面五样东西:
- 一张订单系统的故障模型与不变量表:哪些失败可注入、哪些不变量必须始终成立;
- 一个能跑通选主、复制与分区测试的迷你 Raft,并能说明它的安全边界与性能代价;
- 一套跨分片下单方案:分片键、路由、Saga 或 outbox、补偿与回滚条件齐全;
- 一份对账设计:差异分类、自动修复范围、人工处置入口与收敛判据;
- 一份切换演练表:RTO/RPO、只读降级、回切顺序、验收信号与失败退出条件。
如果这五样能写出来,卷四的演进与治理才有讨论对象:否则“治理”很容易退化成流程名词的堆叠。
从哪开始
第一次读,从1.1 从单机到分布式 开始,按顺序走到第 13 章。手上有具体故障,直接用上面的症状表跳转;要做跨库改造,先读6.3 业务不变量 和13.1 分片迁移 ,再回到对应章节。
全书完整篇目见书架 ,或按顺序从 1.1 走到 13.3。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。