先给结论:分布式事务有解,但解不是某一个中间件,也不是某一种“开箱即用”的模式,而是一整套工程取舍。 这也是我最近几年被问得最多的问题。每次有团队拿着“订单服务扣库存老不一致”来求助,我都会问一句:你确定自己需要的是“分布式事务”,还是你只是需要一个能被追回来、对得上的数据闭环?
先讲个真实案例。去年有个团队找我诊断线上问题,他们的订单服务和库存服务拆成了两个库,核心链路引了一套全局事务中间件。压测一上,TPS刚到几百,数据库会话就全被锁等待占满,接口超时率直线上升。问题的根源倒不是中间件不好,而是他们把“分布式事务”当成了一个可以无缝替换本地事务的增强版事务,没有意识到在分布式环境里,我们要对抗的从来不是某个框架的缺陷,而是网络延迟、机器宕机、消息丢失这些底层事实。
这篇文章我尽量把这件事讲透:为什么分布式事务这么难、主流方案各自解决什么、怎么在真实项目里做选择。尤其会以“订单与库存”这个最高频场景为例,给出两套可以直接落地的设计。内容会比较长,建议先收藏再慢慢看。
1. 先把问题掰开:分布式事务为什么不是“选个中间件”那么简单
1.1 你以为在选方案,其实在和网络分区定律博弈
很多人在刚接触这个问题时,脑子里想的是:单机数据库能靠事务保证ACID,那分布式环境里搞一个“全局事务器”,不也能保证一样的效果吗?
问题就出在这里。
单机事务之所以可行,是因为所有数据都在同一个数据库里,事务管理器拥有一份全局的、确定性的视图。你可以锁行、锁表,可以记录redo/undo日志,可以决定提交或者回滚,而且这一切都发生在同一台机器的可控环境内。跨服务之后,任何一个环节的网络都可能莫名其妙抖动一下。数据库A提交成功了,数据库B那边却因为网络超时根本没有收到“提交”指令——这时候你手上没有任何信息能告诉你B的状态到底是什么。这种“不确定”才是分布式事务真正的敌人。
CAP理论里的partition(分区)不是理论家的恐吓,它是日常现象:交换机震荡、GC停顿、容器迁移、线程池满了,都可能导致一个服务暂时“失联”。在大楼里两个人可以面对面签字画押,但在两栋楼之间签协议就必须依赖通信;只要通信会断,就永远不存在一个方案能让所有人同时完成签字且永远不需要协商。
所以,网上那些“分布式事务六大方案”的文章看起来眼花缭乱,本质都是在回答同一个问题:当网络不可靠时,你怎么设计让步策略?是牺牲可用性去等所有人都确认?还是先放行一部分请求,再靠补偿把账算平?
1.2 单机事务和分布式事务,差的不是事务而是“控制权”
有人可能会说:我们系统已经做得很细了,每个服务都用了数据库事务,为什么跨服务数据还是会乱?
因为每个服务只对自己数据库里那部分数据有“控制权”。
本地事务的ACID,靠的是单点数据库能够对事务内所有操作做裁决。到了分布式环境,订单库和库存库是两套独立的数据库,各自有各自的事务管理器,没有一个公共的上帝视角能同时锁住两边、协调它们的提交。你引入分布式事务中间件,本质上是在所有参与方之上重建一个“中央协调者”。可是这个协调者本身也会挂,也依赖网络。于是你只是把问题从业务层搬到了协调层,并没有消除不确定性。
这也是为什么2PC这类“先prepare、再commit”的方案会有那么多争议。2PC把不确定性尽量压缩到“第二阶段协调者宕机”这一个窗口里,但窗口并没有完全消失。只要这个窗口存在,参与方就必须考虑一个问题:我本地事务已经准备成功、资源锁也持有,可协调者迟迟没通知我到底提交还是回滚,我该怎么办?锁不能一直不放,放了又可能和数据不一致。这个困境不是实现不够好,而是分布式系统里“提交决定”和“执行提交”之间天然存在时间差。
1.3 强一致与最终一致:不存在谁比谁高级
还有一点必须澄清:很多开发者在潜意识里觉得“我要做分布式事务,就是要做强一致”,似乎不强一致就不专业、不安全。这是个很大的误区。
强一致和最终一致不是高低之分,而是不同业务约束下的两种选择。你在京东下单,页面显示“订单已提交,请付款”,这本身就是一次可用性优先的选择;此时后台库存还没扣减,只有当你付款动作真正发生的那一刻,系统才会去锁定库存。这一小段不一致窗口用户完全感知不到,就算感知到了,也只是看到“库存紧张”之类的提示。可如果你是处理支付扣款,用户余额不允许多扣,那你对一致性的要求就完全不同,可能要考虑TCC或者带锁的本地事务。
“最终一致”不等于“最终乱七八糟”。它说的是经过一段可预期的时间后,数据会收敛到一致状态。除非极端故障,否则这个收敛时间通常只有几百毫秒到几秒,用户可以接受,业务也承担得起。把精力花在准确判断“哪些场景可接受短暂不一致、哪些场景绝对不能”上,比盲目找一个万能框架要重要得多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 主流方案的真实角色与代价:从XA到Seata AT逐个排雷
2.1 XA/2PC:教科书里最“正经”的方案,现实里最不敢用
先聊最“正统”的解法,X/Open XA规范下的两阶段提交。这也是很多刚接触分布式事务的人最先学到的方案。
两阶段提交的思路很清晰:先让所有参与方做prepare,各自把本地事务执行到可提交状态并持有资源锁,然后全部返回成功,再由协调者发起commit;只要有一个人prepare失败,就全员rollback。这套逻辑在理论上非常漂亮,以至于很长一段时间里,“分布式事务”和“XA”几乎是
