知其然,知其所以然
分布式事务 2026-10-17

三阶段提交为什么很少用

用协议模型穷举实测 3PC 为什么很少用:没有分区时 2PC 在 7 个崩溃点里有 1 个阻塞、3PC 的 10 个都不阻塞;叠加网络分区后 2PC 的 35 个场景 17 个阻塞、0 个不一致,3PC 的 50 个场景 0 个阻塞、6 个不一致;3PC 还多 6 条消息、多一个往返。

分布式事务 三阶段提交 3PC 2PC 协议建模 枚举 动画演示
分布式事务 2026-10-17

XA 事务:MySQL 的 XA 语句实验

实测 MySQL 的 XA 事务:状态机里 ACTIVE 不能 COMMIT、IDLE 不能写;prepare 之前断开连接会回滚、prepare 之后留在服务端;prepared 事务的行锁让别的写等到 1205 超时;kill -9 重启后 XA RECOVER 能看到、锁被恢复;跨两个实例的 XA 比普通事务多 5 次 redo fsync、中位数 3.4 倍。

分布式事务 XA MySQL 两阶段提交 XA RECOVER 真实验证 动画演示
分布式事务 2026-10-17

TCC:Try、Confirm、Cancel 的设计要点

用两个 MySQL 实例上的账户和库存服务实测 TCC:Try 把资源预留到冻结列、Confirm 转成已用、Cancel 退回;订单 A 在中间停 500 ms,同一行的订单 B 在 TCC 下 2.5 ms、在 XA 下 423.3 ms;检查和预留写成两条语句会多卖 15 件;崩溃订单留下的预留要靠 xid 记录才能安全释放。

分布式事务 TCC Try Confirm Cancel MySQL 真实验证 动画演示
分布式事务 2026-10-17

TCC 的空回滚、悬挂与幂等

实测 TCC 的三个坑:Cancel 先到而 Try 没执行(空回滚)会让朴素版多退 80;Cancel 先到、Try 后到(悬挂)让预留永久卡住;重复的 Confirm / Cancel 让 spent 记成 160。穷举 23 条消息顺序:朴素 14 条、宽容 15 条终态不对,带 tcc_log 防护的 0 条;防护让 Try 慢 2.2 倍,tcc_log 不能过早清理。

分布式事务 TCC 空回滚 悬挂 幂等 tcc_log MySQL 真实验证 动画演示
分布式事务 2026-10-17

Saga:编排式与协同式的区别

用订单、库存、支付三个服务实测 Saga 的两种写法:编排式一个编排器调用三个服务(21.3 ms),协同式用 RabbitMQ 事件接力(3 条消息);支付失败时补偿路径不同、终态相同;库存服务挂 2 秒编排式 0.63 s 取消、协同式 2.06 s 完成;加一个积分步骤,编排式改 1 行,协同式要改 2 个已有服务的订阅。

分布式事务 Saga 编排式 协同式 RabbitMQ MySQL 真实验证 动画演示
分布式事务 2026-10-17

Saga 的补偿:补偿失败怎么办

实测 Saga 补偿失败怎么办:被吞掉的补偿失败让 400 单里 9 单永久占着库存;指数退避重试 2 秒内 7 次调用(固定间隔 21 次),补偿不幂等会把库存加成 102;补偿不是回滚(手续费、短信撤不回);永久失败进人工队列 3 个;不可补偿步骤放前面 81 个订单发了通知又被取消。

分布式事务 Saga 补偿 重试 幂等 人工队列 MySQL 真实验证 动画演示
分布式事务 2026-10-17

Saga 的隔离性缺失:脏读与补偿冲突

实测 Saga 没有隔离性的后果:中间状态被别人读到(1007 次读里 506 次错误拒绝)、绝对值补偿覆盖并发更新(200 次里丢 90 次)、预留窗口里到达的 27 个买家全被拒;相对增量补偿把丢失更新降到 0,语义锁(pending 列)把错误拒绝降到 0。

分布式事务 Saga 隔离性 脏读 丢失更新 语义锁 MySQL 真实验证 动画演示
分布式事务 2026-10-17

Outbox 模式:本地事务写事件

实测双写的问题与 Outbox 的修复:kill -9 在两次操作之间,先写库再发消息丢事件、反过来出幽灵事件;1000 单 3% 失败率下 A 丢 34 个、B 幽灵 30 个,Outbox 丢 0、幽灵 0、重复 20 条;写 outbox 多 40% 的延迟,每行约 149 字节。

分布式事务 Outbox 双写 MySQL Kafka 真实验证 动画演示
分布式事务 2026-10-17

Outbox 的发布:轮询与 CDC

实测 Outbox 的两种发布方式:轮询的延迟约等于间隔的一半(10 ms 间隔 7.0 ms,1000 ms 间隔 552.7 ms),游标轮询会因 id 顺序不等于提交顺序丢 142 / 600 个事件,多个 relay 不加锁重复 17800 条,SKIP LOCKED 为 0;CDC 延迟 1.2 ms、不丢、按提交顺序,代价是复制槽保留 WAL(9 万个事件落后 37.2 MiB)。

分布式事务 Outbox CDC 逻辑解码 PostgreSQL Kafka 真实验证 动画演示
分布式事务 2026-10-17

事务消息:半消息与回查

用真实的 RocketMQ 5.5.1 和 MySQL 实测事务消息:半消息在本地事务提交前对消费者不可见(1643 ms),回滚则丢弃;返回 UNKNOW 时 broker 回查并按订单是否存在 COMMIT;生产者 kill -9 后,没声明 topic 的新生产者收不到回查,3 次后半消息被丢弃,声明了 topic 的新生产者 2997 ms 收到回查并 COMMIT;回查一直 UNKNOW 到上限也会丢弃。

分布式事务 事务消息 半消息 回查 RocketMQ MySQL 真实验证 动画演示
分布式事务 2026-10-17

幂等键:去重表的设计

实测幂等键的去重表设计:200 个 key 各 8 个并发重复请求,先查后插让业务执行了 1590 次,先插唯一键正好 200 次;去重记录与业务不在同一个事务里,1000 个 key 里丢 201 个或重复 210 个,同一个事务 0;状态型幂等键与租约;去重表 30 万 key 13.5 MiB;保留期短于重试窗口会再执行一次。

分布式事务 幂等 幂等键 去重表 MySQL 唯一索引 真实验证 动画演示
分布式事务 2026-10-17

消息重复与乱序:消费端怎么处理

实测消费端怎么处理重复和乱序:RabbitMQ 先处理再 ack 重复 1 条、先 ack 再处理丢 1 条、auto-ack 丢 199 条;两个消费者快慢不同乱序 12 条;Kafka 按实体做 key 实体内 0 条乱序、不设 key 1322 条;版本号解决乱序(status 错 58 到 0)、去重解决重复(counter 错 92 到 0),合用才全对。

分布式事务 消息重复 消息乱序 RabbitMQ Kafka 版本号 去重 MySQL 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号