2025-09-21
微服务与分布式
0

目录

分布式事务与 XA 协议
XA协议原理剖析:两阶段提交(2PC)
阶段一:准备阶段
阶段二:提交阶段
场景一:所有参与者均反馈Yes
场景二:任何参与者反馈No或超时
2PC的优缺点
Seata XA 模式深度解析
Seata架构与 XA 模式流程
Seata XA 模式存在的问题
数据锁定
协议阻塞
性能差
Seata XA 模式的优缺点
Spring Cloud Alibaba 集成 Seata XA 模式实战
XA模式优缺点与适用场景
优点总结
缺点总结:
适用场景
总结

分布式事务是分布式系统开发中的一大挑战,XA 协议作为经典的强一致性解决方案,基于 两阶段提交(2PC) 协议来保证所有事务参与者要么全部成功,要么全部失败。本文将深入剖析 XA 协议的原理,并通过 Seata 框架实现 XA 模式的实际应用。

分布式事务与 XA 协议

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统节点上。XA是由X/Open组织提出的分布式事务处理(DTP,Distributed Transaction Processing)规范,旨在保证分布式事务的强一致性(ACID原则),几乎所有主流数据库(如MySQL、Oracle等)都对XA规范提供了支持。

XA协议通过 两阶段提交(2PC) 机制,协调多个 资源管理器(RM),确保在分布式事务中,所有参与者要么全部提交,要么全部回滚。

在DTP模型中,核心组件包括:

  • 应用程序(AP):定义事务边界(即事务的开始和结束),并在事务边界内对资源进行操作。

  • 事务管理器(TM):负责分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚等。在Seata中,TM通常指开启了全局事务的业务程序。

  • 资源管理器(RM):如数据库、文件系统等,并提供访问资源的方式。在Seata中,RM指参与分布式事务的每个微服务。

XA协议原理剖析:两阶段提交(2PC)

XA 协议的核心是两阶段提交(2PC),其基本思想是将事务的提交过程分为两个阶段来执行。

阶段一:准备阶段

准备阶段的主要目的是 确认所有事务参与者是否都准备好提交事务,具体步骤如下:

  1. 协调者询问:事务协调者(TM)向所有参与者(RM)发送事务内容,询问是否可以提交事务,并等待所有参与者答复。

  2. 参与者执行:各参与者执行事务操作,将Undo和Redo信息记入事务日志中(但不提交事务)。

  3. 参与者反馈:如果参与者执行成功,给协调者反馈Yes(可以提交);如果执行失败,则反馈No(不可提交)。

阶段二:提交阶段

提交阶段的主要目的是根据 准备阶段的反馈结果,决定是真正提交事务还是回滚事务

场景一:所有参与者均反馈Yes

协调者提交请求:协调者向所有参与者发出正式提交事务的请求(即Commit请求)。

  1. 参与者提交:参与者执行Commit请求,并释放整个事务期间占用的资源。

  2. 参与者确认:各参与者向协调者反馈Ack(应答)完成的消息。

  3. 完成事务:协调者收到所有参与者反馈的Ack消息后,完成事务提交。

场景二:任何参与者反馈No或超时

  1. 协调者回滚请求:协调者向所有参与者发出回滚请求(即Rollback请求)。

  2. 参与者回滚:参与者使用阶段一中的Undo信息执行回滚操作,并释放整个事务期间占用的资源。

  3. 参与者确认:各参与者向协调者反馈Ack完成的消息。

  4. 完成中断:协调者收到所有参与者反馈的Ack消息后,完成事务中断。

2PC的优缺点

优点:

  • 强一致性:满足ACID原则,是分布式事务强一致性的经典解决方案。

  • 简单易懂:方案实现起来相对简单,主要数据库都支持,对业务侵入低。

缺点:

  • 同步阻塞问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈。

  • 单点故障问题:如果协调者(TM)出现故障,参与者(RM)将一直处于锁定状态。

  • 数据一致性问题:在阶段二中,如果发生局部网络问题,一部分参与者收到了提交消息,另一部分没收到,会导致节点间数据不一致。

Seata XA 模式深度解析

XA 模式是从 1.2 版本支持的事务模式,Seata XA 模式是利用事务资源(数据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一种事务模式。Seata 对 XA 模式进行了封装,使其更易于在微服务架构中使用。

主要特点:

  • 采用 DataSourceProxyXA 作为数据源代理,替代AT模式的 DataSourceProxy
  • 通过 @GlobalTransactional 注解标记分布式事务入口
  • 在第一阶段,RM 执行业务 SQL 但不提交,只注册分支事务
  • 在第二阶段,由 TM 根据分支状态决定提交或回滚

Seata架构与 XA 模式流程

image.png

在 Seata 定义的分布式事务框架内,XA 模式利用事务资源(数据库等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务。

执行阶段(Execute):

  • 开启全局事务:TM 向 TC(Seata-Server)发起全局事务的开启请求,TC生成全局唯一的XID。

  • 注册分支事务:每个 RM 执行业务 SQL 前,会向TC注册分支事务,并将XID与本地事务关联。

  • 执行SQL并准备:RM执行业务SQL,但不提交(数据库层面由XA驱动管理),然后执行xa_prepare(或等效操作)。

报告状态:RM 将本地事务执行状态(成功或失败)报告给 TC。

完成阶段(Finish):

  • TC决策:TC 根据所有分支事务的报告状态决定全局事务是提交还是回滚。

  • 提交/回滚:TC 通知所有 RM 执行 xa_commitxa_rollback

  • 资源释放:RM 完成最终操作并释放事务资源。

Seata XA 模式的数据源代理设计对开发者友好,旨在透明化 XA 编程模型。它支持基于普通 DataSource 创建 XA 连接,无需开发者专门配置 XADataSource

Seata XA 模式存在的问题

数据锁定

数据在整个事务处理过程结束前,都被锁定,读写都按隔离级别的定义约束起来。

思考

数据锁定是获得更高隔离性和全局一致性所要付出的代价。

补偿型 的事务处理机制,在 执行阶段 即完成分支(本地)事务的提交,(资源层面)不锁定数据。而这是以牺牲 隔离性 为代价的。

另外,AT 模式使用 全局锁 保障基本的 写隔离,实际上也是锁定数据的,只不过锁在 TC 侧集中管理,解锁效率高且没有阻塞的问题。

协议阻塞

XA prepare 后,分支事务进入阻塞阶段,收到 XA commit 或 XA rollback 前必须阻塞等待。

思考

协议的阻塞机制本身并不是问题,关键问题在于 协议阻塞 遇上 数据锁定。

如果一个参与全局事务的资源 “失联” 了(收不到分支事务结束的命令),那么它锁定的数据,将一直被锁定。进而,甚至可能因此产生死锁。

这是 XA 协议的核心痛点,也是 Seata 引入 XA 模式要重点解决的问题。

基本思路是两个方面:避免 “失联” 和 增加 “自解锁” 机制。

性能差

性能的损耗主要来自两个方面:一方面,事务协调过程,增加单个事务的 RT;另一方面,并发事务数据的锁冲突,降低吞吐。

思考

和不使用分布式事务支持的运行场景比较,性能肯定是下降的,这点毫无疑问。

本质上,事务(无论是本地事务还是分布式事务)机制就是拿部分 性能的牺牲 ,换来 编程模型的简单 。

与同为 业务无侵入 的 AT 模式比较:

首先,因为同样运行在 Seata 定义的分布式事务框架下,XA 模式并没有产生更多事务协调的通信开销。

其次,并发事务间,如果数据存在热点,产生锁冲突,这种情况,在 AT 模式(默认使用全局锁)下同样存在的。

所以,在影响性能的两个主要方面,XA 模式并不比 AT 模式有非常明显的劣势。

AT 模式性能优势主要在于:集中管理全局数据锁,锁的释放不需要 RM 参与,释放锁非常快;另外,全局提交的事务,完成阶段 异步化

Seata XA 模式的优缺点

优点:

  • 强一致性:得益于 XA 协议,满足 ACID 特性。

  • 数据库支持广泛:主流支持 XA 协议的数据库均可使用。

  • 低侵入性:开发者通常只需关注 @GlobalTransactional 注解,无需深入修改业务代码。

缺点:

  • 性能开销:一阶段需要锁定数据库资源,直到二阶段结束才释放,在高并发场景下对性能影响较大。

  • 依赖数据库 XA 支持:其能力依赖于底层数据库对 XA 协议的实现质量。

Spring Cloud Alibaba 集成 Seata XA 模式实战

接下来我们设计一套基于 Seata XA 模式的分布式事务实现方案。

环境准备

  • Seata Server (TC):已部署并运行,并使用 Nacos 作为注册中心和配置中心。

  • 支持XA的数据库:如MySQL 5.7.17及以上版本。

基于 Spring Cloud Alibaba 构建 cloud-seata-xa 项目,模块如下

  • cloud-seata-xa-order
  • cloud-seata-xa-account
  • cloud-seata-xa-storage

代码实现可下载 cloud-seata-xa

提示

从编程模型上,XA 模式与 AT 模式保持完全一致,只需要修改数据源代理,即可实现 XA 模式与 AT 模式之间的切换。

Naocs 配置

在同分组下,根据服务中 seata.service.vgroup-mapping 定义的分组名称配置信息,内置的文本为集群名称 default

yml
seata: # 是否开启spring-boot自动装配 默认true enabled: true # 是否开启数据源自动代理 默认 true enable-auto-data-source-proxy: true # 是否使用JDK代理作为数据源自动代理的实现方式,默认false,采用CGLIB作为数据源自动代理的实现方式 use-jdk-proxy: false # 数据源代理模式 默认 AT data-source-proxy-mode: XA # Seata 应用ID,默认${spring.application.name} application-id: ${spring.application.name} # 事务分组 - 用于TC集群名 tx-service-group: seata-xa-group # 添加以下配置 service: vgroup-mapping: seata-xa-group: default # 你的事务分组对应的集群名称 disable-global-transaction: false

image.png

XA模式优缺点与适用场景

优点总结

  • 强一致性:严格遵循ACID,数据一致性高。

  • 模型简单:理解和使用相对简单,尤其是与Seata集成后。

  • 数据库原生支持:依赖数据库自身XA实现,稳定可靠。

  • 无代码侵入(低侵入):业务代码几乎无需为分布式事务做额外修改。

缺点总结:

  • 性能瓶颈:同步阻塞和资源锁定时间长,吞吐量低,不适合高并发场景。

  • 依赖数据库:性能和质量受数据库XA实现影响。

  • 单点问题:TM(协调者)宕机可能导致资源阻塞(虽然后续有Seata TC保障,但传统2PC存在此问题)。

适用场景

  • 对强一致性要求极高的业务场景,如金融核心交易。

  • 事务执行时间相对确定且较短的操作。

  • 系统并发量不是极端高,可以接受XA协议性能损耗的场景。

总结

XA 协议通过两阶段提交(2PC) 机制,为分布式事务提供了强一致性的保证,是分布式事务领域经典且重要的解决方案。Seata 框架对 XA 进行了封装和优化,降低了开发复杂度,使得开发者能够通过简单的注解和配置,快速在微服务体系中引入强一致性分布式事务能力。

然而,XA 协议的同步阻塞和性能问题也是其固有的局限性。因此,在选择分布式事务方案时,需要根据实际业务场景对一致性和性能的要求进行权衡。对于追求高性能和最终一致性的场景,可以考虑 Seata 的 AT 模式或TCC 模式等柔性事务方案。

本文作者:柳始恭

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!