1. 为什么还要聊XA:分布式事务的最后一公里
先从一个我上个月刚处理的线上事故说起。某个核心订单服务在压测环境下,库存扣减成功但订单创建失败,一查日志,发现是库存服务把数据回滚了,订单服务自己提交了事务,两边数据直接不一致。这种问题在单体应用里根本不存在,但一旦拆成微服务、拆了库,分布式事务就成了绕不过去的坎。
SEATA分布式事务是目前国内用得最多的开源分布式事务方案,它本身提供了AT、TCC、SAGA、XA四种模式。这里面的XA模式,本质上不是Seata创新的东西,而是把数据库标准里早就定义的XA协议接进了Seata框架,让Seata的TM、TC、RM三个核心角色配合数据库自己的事务管理器,完成跨服务的强一致性事务控制。
这篇文章我想把XA模式从原理到实操完整讲一遍。内容适合这几类人看:正在做订单、库存、支付这类强一致场景的后端开发,准备Seata分布式事务面试题的技术候选人,以及已经在用AT模式但想搞清楚什么时候该切XA模式的架构师。
先给一个结论:如果在面试里被问到“Seata的几种模式怎么选”,XA模式就是那个“性能差但一致性最强、实现最简单”的选项。它不适合所有场景,但在某些必须保证强一致的业务里,它是性价比最高的方案,没有之一。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Seata与XA模式整体设计思路拆解
2.1 分布式事务到底在解决什么问题
在拆Seata之前,先把问题定义清楚。分布式事务的核心场景,就是一次业务操作涉及多个独立的资源,比如订单库、库存库、账户库,它们分布在不同的数据库实例甚至不同的物理机上。单体时代,一个数据库事务就能搞定;微服务加分库之后,每个服务有自己独立的本地事务,但跨服务之间没有统一的事务边界。
这个时候会出现什么情况?订单创建成功了,库存扣减失败回滚了,用户拿着一笔付了钱但没货的订单来找客服。或者库存扣了,订单没创建成功,库存无声无息地消失了。无论是哪种,都属于数据不一致问题,也就是分布式事务要解决的。
业界解决这个问题的思路大致分两类:一类是强一致方案,代表就是XA两阶段提交,所有参与方要么全成功要么全失败;另一类是最终一致方案,代表是本地消息表、事务消息、TCC、SAGA,允许短暂的不一致,通过补偿机制最终对齐。Seata牛逼的地方在于,它把这两类方案都收进了同一个框架,开发者只需要选模式,然后在一个注解上改个值,就能切换事务策略。
2.2 Seata的三个角色:TM、TC、RM
Seata分布式事务原理里最关键的就是理解三个角色:TM(Transaction Manager,事务管理器)、TC(Transaction Coordinator,事务协调器)、RM(Resource Manager,资源管理器)。很多面试题直接考这个,但光背概念没用,得知道它们在一次分布式事务里分别干了什么。
拿一个订单创建流程举例:用户下单,事务发起方是订单服务,这个订单服务就是TM,它负责向TC发起全局事务的开启、提交或回滚指令。TC是独立部署的Seata Server,它负责记录全局事务的状态,协调所有参与者。订单、库存、账户三个服务各自内部都有RM,RM负责管理分支事务,也就是本地事务,以及向TC注册分支、上报状态。
整个流程是这样的:TM告诉TC“我要开一个全局事务”,TC生成一个全局事务ID(XID);XID通过调用链传递到库存服务和账户服务;每个服务的RM收到XID后,执行自己的本地事务,然后向TC注册分支事务;业务全部执行完,TM向TC说“可以提交了”,TC再通知所有RM提交各自的分支事务,或者某个环节出错了,TC通知所有RM回滚。这个模型不只是XA在用,AT模式也完全复用这一套架构,区别只在于RM底层的实现机制不同。
2.3 AT模式和XA模式的差异与选型逻辑
既然Seata的四种模式里,AT模式在框架里是出镜率最高的,为什么还要单独讲XA?因为有相当一部分场景,AT模式并不能胜任。
AT模式的核心思路是“业务无侵入”。它通过拦截SQL,在业务数据变更的同时记录undo_log回滚日志。执行阶段,AT模式只是自动把每个本地事务提交掉;如果后续某个分支失败需要回滚,TC通知RM根据undo_log去反向补偿,把数据恢复成原样。这种方案性能好,业务代码不用改SQL,非常适合大多数互联网业务。
但AT模式有三个明显的弱点。第一,它只能保证最终一致性,回滚是补偿式的,数据在中间状态是可见的,强一致场景下可能有问题;第二,undo_log补偿不是万能的,如果回滚期间有别的请求修改了同一行数据,就会产生脏写,需要额外的全局锁保护;第三,AT模式依赖Seata框架对SQL的解析和拦截,在一些复杂的SQL写法下会出现解析问题。
XA模式走的是另一个极端:事务执行期间,所有参与方的资源直接被数据库锁住,要么全部提交,要么全部回滚,中间状态对业务不可见,是真正的强一致。代价就是锁的持有时间被拉长,并发能力被削弱。所以选型逻辑很清晰:对一致性要求极高、并发量不大、数据库本身支持XA协议的核心链路,用XA;对一致性要求不极致、追求吞吐量的场景,用AT。
3. 核心细节解析与实操要点
3.1 XA协议的两阶段提交到底怎么运作
XA模式的核心就是两阶段提交,这是数据库领域的老协议了,1991年左右就进了X/Open标准。我在实际排查问题的时候发现,不少人知道“两阶段”这个名词,但说不清楚两个阶段到底在做什么、各自有什么风险。
第一阶段叫准备阶段,Second Phase Commit的前奏。事务协调者(也就是Seata里的TC)向所有参与者发出prepare请求。每个参与者收到请求后,执行事务操作到一半,但不提交,而是把事务状态改为“可提交”,然后向协调者回复“我准备好了”。这个状态的学名叫“就绪状态”,数据库会把这个事务的修改写入事务日志,并且持有相关行或表的锁。
第二阶段是提交阶段。
