连载中 3/18

2PC 与 XA:强一致的经典与枷锁

2026-06-15 · 7361 阅读 · 0 评论 · 0 赞

DBA 的一个建议

拆微服务前,老王的系统里有块老业务:账户域和订单域分属两个库,但财务要求两边要么同时生效、要么同时不生效,中间态一秒都不能出现。DBA 给的建议是上 XA:「数据库原生支持,改个配置就有强一致,不用改业务代码。」听起来像免费的午餐——天下没有这种午餐,先把 2PC 的原理和价签看清楚。

2PC:先表决,再执行

2PC(两阶段提交)安排一个协调者指挥所有参与者(各自的数据库),流程两阶段:

第一阶段(表决):协调者向所有参与者发 prepare。参与者执行事务里的全部操作——注意是执行但不提交——把 undo/redo 日志写好,锁住涉及的行,然后投票:我这边能提交(yes)或不行(no)。

第二阶段(执行):协调者收集全部选票。全 yes,广播 commit,参与者正式提交;有一个 no 或有人超时未应答,广播 rollback,全员回滚。

生活版比喻:AA 制聚餐,组织者挨个问「都带钱了吗」,全员点头才开始收钱,有一个人摇头整个饭局取消。表决制保证要么都吃上,要么都不吃——这就是强一致的形状。

枷锁一:同步阻塞

代价从第一阶段就开始付:参与者 prepare 之后到收到全局指令之前,行锁一直握在手里不放——它必须锁住才能保证随时可提交或可回滚。锁的持有时长等于「最慢参与者的应答时间 + 两轮网络传输」,任何一个参与者慢半拍,全体参与者的热点行都在等它。老王压测数据:同链路本地事务 TPS 三千,套上 XA 掉到三百,一个数量级起步。高并发的链路,这个价格付不起。

枷锁二:协调者单点

更要命的是第二阶段的空窗:协调者收齐选票、还没来得及广播 commit 就宕机——所有参与者握着锁、拿着写好的日志,永远等不到那条指令。参与者不能自己猜着提交:万一别的参与者投的是 no 呢?猜错就是数据不一致。它们只能干等,直到人工介入。2PC 用表决换强一致,表决的核心信息却押在协调者一个点上——这是协议与生俱来的单点,不是实现问题。

枷锁三:不一致窗口

即便协调者活着,广播 commit 的瞬间它也可能挂:指令送达了一半参与者,另一半没收到——一半提交一半回滚,强一致在最需要它的时刻破了功。2PC 缩小了不一致的概率窗口,但没有消灭它。3PC 加了 CanCommit 预询和参与者超时自救,缓解了阻塞、又引入了新的一致性漏洞(超时猜 commit 可能猜错),工程上反而罕见——记住 2PC 就够,3PC 知道有这回事即可。

XA:2PC 的数据库标准化

XA 是把 2PC 做成数据库接口标准的产物:MySQL 原生支持 XA 语句,Java 侧由 JTA 规范和 Atomikos、Narayana 这类事务管理器当协调者。接入方式对业务近乎透明——换个数据源配置,SQL 照写。它的价值与价签都来自「不改代码」:改造成本最低,运行成本最高

维度表现
一致性强一致(存在窄的不一致窗口)
吞吐同步阻塞,通常掉一个数量级
可用性协调者单点,故障需人工介入
业务侵入几乎为零(换数据源)
适用低并发、跨库强一致、遗留系统不改代码

老王的取舍

最后老王只在账户域那块老业务上留了 XA:并发低、财务红线硬、且那两个库的代码没人敢动——三条件同时命中,XA 才划算。下单主链路坚决绕开。这套判断浓缩成一句话:业务不改一行代码的方案,一定会用性能还债;性能还不起的地方,就得用业务改造来换——所谓业务改造,就是下一篇的主角 TCC。

小结

2PC 一句话:先表决再执行换来跨库强一致,同步阻塞、协调者单点、不一致窗口是三道天生的枷锁;XA 把它标准化成「接入便宜、运行昂贵」,只配低并发场景。互联网的高并发链路要兼顾可用性,就得把事务逻辑搬进业务里——下一篇:TCC,Try-Confirm-Cancel。

503

10 年全栈工程师 · 503咖啡馆主理人

#分布式事务#2PC#XA#强一致#两阶段提交

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞