外观主题
阅读语言

分布式事务 —— 预冻结 + 状态机,从结构上杜绝脑裂

软件 本站软件 3小时前
https://yxp.hk/p/2liPsv

📦 开源仓库:learn_distributed_txn · 纯 Python 标准库 · 学习演示项目

跨库转账类事务,经典的 2PC 要跨库投票,一投票就有脑裂风险。这个仓库演示另一种思路:数据库之间完全不通信、不共识,所有协调、锁定、状态推进、补偿全部收进业务层框架,靠「预冻结 + 状态机」从外部看呈现原子性,内部走最终一致。

核心思路

  • 硬约束:资产变更必须走框架,禁止绕过直写节点;资产支持冻结标记(不动真实值的本地事务标记,带 TTL);每个操作携带全局事务 ID + 幂等键
  • 库与库之间:彻底互不感知——不通信、不共识,各自只保证单机本地一致

状态机

INIT           事务创建,尝试冻结
FROZEN         双方冻结就绪,待扣真实值
ROLLBACK       需要补偿
ROLLED_BACK    补偿完成(终态)
SUCCESS        正向全部完成(终态)
MANUAL_REVIEW  重试耗尽,转人工(终态)

补偿动作由阶段决定:已真实扣减(COMMITTED)→ 退款;只冻结(FROZEN)→ 解冻(真实值未动)。

两层自愈 + 兜底

  1. 第一层:轮询器 + 死信——持续扫描非终态事务;下游故障进死信队列,消费时先重连核实资产真实状态再决定继续正向还是补偿,指数退避;重试耗尽升级 MANUAL_REVIEW 并告警
  2. 第二层:节点启动自检——节点宕机期间收不到补偿指令,重启后主动查全局事务中心、核对本地冻结标记,在自己的本地事务里完成解冻/退款,再写回全局状态
  3. 兜底:离线对账 + 快照——定期交叉核对流水与全局记录;孤儿冻结(有标记无全局记录)自动解冻并告警;全局事务库定期快照防丢

演示场景(run_all.py 自动跑 7 例)

场景 覆盖机制 结果
正常下单(扣余额+扣库存) 正向流程 + 幂等重放 INIT→FROZEN→SUCCESS
冻结失败(余额不足) 冻结期回滚 商家冻结解冻,库存不动
商家 COMMIT 拒绝 提交期回滚 + 退款 ROLLED_BACK
商家分片隔离后恢复 轮询器 + 死信续跑 SUCCESS
商家进程宕机重启 节点启动自检回滚 ROLLED_BACK
孤儿冻结 + 全局库丢失 离线对账自动解冻 + 快照恢复 清理 + 告警
商家持续不可达 重试耗尽 → 人工 MANUAL_REVIEW + 告警

学习演示项目:生产化需要把 JSON 存储换成真数据库、给轮询器加选主、死信换真 MQ、自检与轮询去重等。

运行

python run_all.py

纯 Python 标准库,零第三方依赖,一键跑完所有演示场景后自动退出。
仓库:github.com/yxpil/learn_distributed_txn,欢迎 Star 与提 Issue。