微服务分布式事务实战:从原理到 Alibaba Seata 完整落地指南
在微服务架构大行其道的今天,随着业务规模的不断扩大,服务拆分、数据库分库分表已经成为企业系统架构设计的常态。这种拆分虽然提升了系统的可扩展性、可维护性和开发效率,但随之而来的分布式事务问题,却成为保证数据一致性的最大拦路虎。例如一个简单的用户下单操作,背后需要同时完成创建订单、扣减商品库存、扣减用户账户余额三个核心步骤,这三个步骤分别对应三个独立的服务和数据库,任何一步执行失败,都可能导致数据不一致,进而引发业务异常和经济损失。
本文将从分布式事务的基础理论讲起,深度解析 CAP 理论、BASE 理论、两阶段提交(2PC)、三阶段提交(3PC)等核心概念,再带你全面掌握阿里巴巴 Seata四大事务模式(XA、AT、TCC、SAGA),从模式原理、环境配置到实战落地,一步步拆解操作细节,一站式搞定微服务场景下的分布式事务难题。
一、Seata 是什么
Seata 是一款开源的高性能分布式事务解决方案,由阿里巴巴中间件团队开源研发,后续捐赠给 Apache 软件基金会,成为 Apache 顶级开源项目。它专为微服务架构设计,提供了AT、TCC、SAGA、XA四种灵活的事务模式,能够适配不同业务场景的需求,为微服务场景提供一站式、低侵入、高可用的分布式事务管理能力,有效解决跨服务、跨数据库的数据一致性问题。
简单来说:Seata 就像是微服务架构下的分布式事务管家,它能够协调各个独立服务的事务执行,确保跨服务、跨数据库的一系列操作要么全部成功,要么全部失败,从根本上避免数据不一致的问题。
二、什么是分布式事务
2.1 回顾本地事务 ACID
在了解分布式事务之前,我们先回顾一下大家熟悉的本地事务(即单库事务),它的核心是满足四大特性,这也是事务一致性的基础:
原子性(Atomicity):事务中的所有操作是一个不可分割的整体,要么全部执行成功,要么全部执行失败,不存在部分成功、部分失败的情况。
一致性(Consistency):在事务开始之前和事务结束之后,数据库的完整性约束不会被破坏,写入的数据必须完全符合所有预设规则,包括数据精度、关联性等。
隔离性(Isolation):数据库允许多个并发事务同时对数据进行读写和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致的数据不一致,可通过设置不同隔离级别平衡性能和安全性。
持久性(Durability):事务处理结束后,对数据的修改将永久写入存储介质(如数据库磁盘),即便系统发生故障(如断电、宕机),修改后的数据也不会丢失。
2.2 分布式事务的诞生
在传统单体架构中,所有业务逻辑都集中在一个应用中,所有数据也存储在一个数据库中,本地事务就能满足数据一致性需求。但在微服务架构下,情况发生了根本变化:
订单服务、库存服务、账户服务等业务服务独立部署、独立维护,彼此通过 RPC 或 Restful 接口通信。
每个服务对应独立的数据库,数据不再集中存储,而是按业务域拆分到不同的数据库中,实现数据隔离。
一次完整的业务操作(如下单),需要跨多个服务、多个数据库执行一系列操作,这些操作必须保持一致性。
这就构成了分布式事务:所谓分布式事务,就是在分布式系统中,为了保证数据的一致性和完整性,对多个节点(服务、数据库)上的数据进行操作的事务。其核心目标是保证多个节点上的数据操作同时成功或同时失败,本质上就是解决分布式场景下的数据一致性问题。
三、分布式事务问题演示
为了让大家更直观地理解分布式事务问题,我们以最经典的下单业务为例,复现分布式事务不一致的场景,该场景包含三个核心操作:
订单服务:创建用户订单,将订单信息写入订单数据库。
库存服务:根据订单中的商品信息,扣减对应商品的库存,更新库存数据库。
账户服务:根据订单金额,扣减用户账户中的余额,更新账户数据库。
3.1 项目结构
为了演示该场景,我们搭建了一个简单的微服务项目,项目结构如下:
order-service:订单服务,负责订单的创建、查询、修改等业务,对应订单数据库。
storage-service:库存服务,负责商品库存的管理、扣减等操作,对应库存数据库。
account-service:账户服务,负责用户账户余额的管理、扣减等操作,对应账户数据库。
三个服务相互独立,通过 RPC 接口通信,各自操作自己的数据库,不存在数据共享。
3.2 问题复现
我们模拟一种异常场景:用户下单时,账户余额不足,此时执行以下操作会出现数据不一致问题:
订单服务:正常执行 SQL,创建订单成功,订单状态为“待支付”或“已创建”。
库存服务:正常调用接口,扣减对应商品的库存,库存数据更新成功。
账户服务:执行余额扣减操作时,发现余额不足,抛出异常,余额扣减失败。
最终结果:库存少了、订单生成了,但用户的钱没扣,这就导致了数据严重不一致——商品库存减少但未收到对应款项,订单已创建但未完成支付流程,后续会引发一系列业务问题(如库存对账异常、订单状态异常等),这就是典型的分布式事务灾难。
四、分布式事务核心理论
要解决分布式事务问题,首先需要掌握分布式事务的核心理论,这些理论是设计和实现分布式事务解决方案的基础,也是理解 Seata 各种事务模式的关键。
4.1 CAP 理论
CAP 理论是分布式系统设计中最基础、最核心的理论,由 Eric Brewer 提出,它指出:分布式系统的三个核心特性不可同时满足,最多只能同时满足其中两个。
C(一致性):所有节点在同一时间访问到的数据是完全相同的,即数据同步实时一致,无论访问哪个节点,得到的结果都是一致的。
A(可用性):系统中的每个请求都能在合理的时间内得到响应,无论请求是否成功,都不会出现无响应的情况,服务始终可用。
P(分区容错性):当分布式系统中出现网络分区(即部分节点之间无法通信)时,系统仍然能够对外提供正常的服务,不会因为网络故障而整体瘫痪。
结论:在实际的分布式系统中,网络环境复杂多变,网络分区是不可避免的(如网络中断、延迟过高),因此分布式系统必须保证 P(分区容错性),在此前提下,只能在CP(强一致性+分区容错)或AP(高可用+分区容错)中二选一。
4.2 BASE 理论
由于 CAP 理论中一致性(C)和可用性(A)不可兼得,而互联网场景中大多需要保证服务的高可用性,因此 BASE 理论应运而生。BASE 理论是 CAP 理论的落地实践,其核心思想是通过牺牲数据的强一致性,换取系统的高可用性和高吞吐量。
基本可用(Basically Available):分布式系统在出现故障时,允许损失一部分功能的可用性,但必须保证核心功能可用。例如,电商平台出现故障时,可暂时关闭评论、收藏等非核心功能,确保下单、支付等核心功能正常使用。
软状态(Soft State):允许系统中的数据存在中间状态,即允许不同节点的数据副本之间的同步存在一定延时,这个中间状态不会影响系统的整体可用性,也不会导致业务异常。
最终一致性(Eventually Consistent):虽然系统在短期内可能存在数据不一致的情况,但经过一段时间的同步和补偿,所有节点的数据最终会达到一致状态,这是 BASE 理论的核心目标。
互联网绝大多数场景(如电商、社交、支付等)都采用 BASE 理论,优先保证服务的可用性和性能,再通过后续的补偿机制实现数据的最终一致性。
4.3 X/Open DTP 分布式事务模型
X/Open 是一个国际标准组织,该组织定义了一套分布式事务处理的标准——X/Open DTP(Distributed Transaction Process Reference Model),这套标准提出了使用两阶段提交(2PC)来保证分布式事务的完整性,为分布式事务的实现提供了规范和依据。
这套标准主要定义了实现分布式事务的规范和 API,具体的实现则由相应的厂商(如数据库厂商、中间件厂商)来完成。其核心定义了三种角色,三者协同工作完成分布式事务:
AP(Application):应用程序,即业务服务(如下单服务、库存服务),负责发起分布式事务,调用各个资源管理器的接口完成业务操作。
RM(Resource Manager):资源管理器,负责管理具体的资源(如数据库、消息队列),应用程序可以通过资源管理器对相应的资源进行有效的控制,同时向事务管理器报告事务执行状态。
TM(Transaction Manager):事务管理器,也称为事务协调者,负责协调和管理各个子事务(分支事务),统一决策分布式事务的提交或回滚,是分布式事务的核心协调组件。
X/Open DTP 模型的核心协议是XA 协议,该协议主要定义了全局事务管理器(TM)和局部资源管理器(RM)之间的接口,用于协调各个 RM 的事务执行,其底层基于两阶段提交(2PC)机制。
4.4 两阶段提交 2PC
两阶段提交(2PC,Two-Phase-Commit)是 X/Open DTP 标准推荐的分布式事务实现方式,也是最经典的分布式事务协调机制,它将分布式事务的执行过程分为两个阶段,通过 TM 和 RM 的协同工作,保证事务的原子性。
具体分为两个阶段:
准备阶段:事务协调者(TM)向所有参与者(RM)发送准备请求,询问它们是否准备好提交事务。这个请求包含了事务的详细信息,要求参与者对事务进行预处理(执行 SQL 但不提交),并准备好回滚或提交事务所需的所有资源,同时将执行结果和准备状态记录在本地日志中。如果参与者成功执行了预处理,就向 TM 发送 ready 消息,表示已准备好提交;如果执行失败或无法准备,则发送 abort 消息,表示无法提交。
提交 / 回滚阶段:事务协调者(TM)收集所有参与者的响应后,做出最终决策。如果所有参与者都返回 ready 消息,则 TM 决定提交事务,向所有参与者发送 commit 请求,参与者收到请求后正式提交事务、释放资源,并向 TM 发送 ack 消息;如果有任何一个参与者返回 abort 消息,或超时未响应,则 TM 决定回滚事务,向所有参与者发送 rollback 请求,参与者收到请求后回滚事务、释放资源,并向 TM 发送 ack 消息。
优点:能够严格保证事务的原子性,实现简单,易于理解和部署,适用于对数据一致性要求高的场景。缺点:阻塞问题严重,两个阶段都是事务阻塞型的,若 TM 宕机或网络故障,RM 会一直处于阻塞状态,无法释放资源;资源占用久,参与者在准备阶段会锁定相关资源,直到事务提交或回滚才释放,降低资源利用率;数据不一致风险,若提交阶段网络异常,部分 RM 收到 commit 请求并执行,部分未收到,会导致数据不一致。
4.5 三阶段提交 3PC
三阶段提交(3PC,Three-Phase-Commit)是两阶段提交(2PC)的改进版本,其核心目的是解决 2PC 中的阻塞问题,通过增加超时机制和一个预备提交阶段,减少参与者的阻塞时间,提升系统的容错能力。
3PC 共分为三个阶段,具体如下:
CanCommit 阶段:协调者(TM)向所有参与者(RM)发送 CanCommit 请求,询问它们是否有足够的资源和条件执行事务提交操作。此阶段不涉及实际的数据修改,仅做资源校验,参与者根据自身情况返回 Yes 或 No,若所有参与者都返回 Yes,则进入 PreCommit 阶段;若有任一返回 No,则直接终止事务。
PreCommit 阶段:协调者(TM)向所有参与者发送 PreCommit 请求,指示参与者执行事务预处理(执行 SQL 但不提交)。参与者执行完成后,将事务执行结果和准备状态发送给 TM,并记录预提交日志(确保持久化)。若所有参与者都返回 Yes,则进入 DoCommit 阶段;若有任一返回 No 或超时未响应,TM 发送 abort 请求,通知所有参与者回滚事务。
DoCommit 阶段:协调者(TM)向所有参与者发送 DoCommit 请求,指示它们正式提交事务。参与者收到请求后,执行事务提交操作,释放资源,并向 TM 发送 Ack 消息;若参与者在等待 DoCommit 请求时超时,会默认执行提交操作,避免长期阻塞。
优点:通过引入超时机制,减少了 2PC 中的阻塞问题,避免资源被永久锁定;增强了容错能力,即使协调者在 DoCommit 阶段之前出现故障,参与者也能基于预提交状态自主决定继续提交或回滚,降低对协调者的依赖。缺点:实现复杂度远高于 2PC,增加了系统的开发和维护成本;在极端场景下(如网络分区),仍可能出现数据不一致问题,例如参与者超时后自主提交,而协调者实际需要回滚。
4.6 TCC 事务
TCC(Try-Confirm-Cancel)是一种分布式事务解决方案,由 Pat Helland 在 2007 年发表的论文《Life beyond Distributed Transactions: An Apostate’s Opinion》中提出。与 2PC、3PC 依赖数据库原生事务不同,TCC 是一种业务层的分布式事务方案,不依赖资源管理器(RM)对 XA 协议的支持,而是通过对业务逻辑的拆分和接口调用,实现分布式事务的一致性。
TCC 通过将事务操作拆分为三个阶段,由业务代码自主实现事务的准备、确认和回滚,具体如下:
Try 阶段:尝试执行业务操作,完成所有业务检查(如余额是否充足、库存是否足够),并预留必要的业务资源(如冻结部分余额、冻结部分库存)。这个阶段不真正执行事务,仅做资源预留和检查,确保后续操作能够正常执行。
Confirm 阶段:如果所有参与者在 Try 阶段都执行成功,说明所有资源都已预留完成,此时进入 Confirm 阶段,正式完成业务操作,使用之前预留的资源(如将冻结的余额扣减、将冻结的库存扣减),这个阶段是不可逆的。
Cancel 阶段:如果任何一个参与者在 Try 阶段执行失败,说明资源预留存在问题,此时进入 Cancel 阶段,所有参与者回滚在 Try 阶段执行的操作,释放预留的资源(如解冻冻结的余额、解冻冻结的库存),恢复到事务执行前的状态。
TCC 事务属于两阶段提交思想的变体,第一阶段通过 Try 进行资源准备,第二阶段通过 Confirm/Cancel 完成操作的确认和回滚。优点:无需依赖第三方中间件或数据库的原生事务支持,降低了系统复杂度和成本;无需锁定全局资源,资源预留后可快速释放,提高了系统的并发性能和可用性;适用于各种类型的业务场景,只要能够定义出清晰的 Try、Confirm 和 Cancel 逻辑即可。缺点:需要开发人员手动编写三个阶段的业务逻辑,并保证其正确性和一致性,开发难度大、维护成本高;需要考虑各种异常情况(如超时、网络故障)和边界情况,并提供相应的补偿策略和重试机制,进一步增加了系统复杂度和风险。
五、Seata 核心角色与部署
了解了分布式事务的核心理论后,我们重点学习阿里巴巴 Seata 分布式事务解决方案。Seata 基于 X/Open DTP 模型,对核心角色进行了优化和简化,同时提供了多种事务模式,能够快速适配微服务场景的分布式事务需求。
5.1 Seata 三大角色
Seata 定义了三大核心角色,三者协同工作,完成分布式事务的协调和执行,与 X/Open DTP 模型的角色对应,更贴合微服务架构的实际应用:
TC(Transaction Coordinator):事务协调者,是 Seata 分布式事务的核心组件,独立部署为 Seata Server。主要负责维护全局事务和分支事务的状态,接收 TM 的请求,协调所有 RM 的事务执行,最终驱动全局事务的提交或回滚。
TM(Transaction Manager):事务管理器,嵌入在业务服务(AP)中。主要负责定义全局事务的范围,即开启全局事务、提交全局事务或回滚全局事务,同时与 TC 通信,传递全局事务的相关信息。
RM(Resource Manager):资源管理器,嵌入在业务服务(AP)中,与业务服务的数据库关联。主要负责管理分支事务处理的资源,与 TC 通信以注册分支事务、报告分支事务的执行状态,并根据 TC 的指令驱动分支事务的提交或回滚。
5.2 Seata 集成步骤
在微服务项目中集成 Seata 非常简单,只需完成以下三个步骤,即可快速实现分布式事务的管理,这里以 Spring Cloud 微服务为例进行说明:
- 引入依赖:在需要使用分布式事务的微服务(如 order-service、storage-service、account-service)的 pom.xml 文件中,引入 Seata 依赖,确保依赖版本与 Seata Server 版本一致。
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency>- 配置 Seata:在微服务的 application.yml 配置文件中,添加 Seata 相关配置,主要配置注册中心(如 Nacos)地址、事务服务组等信息,确保微服务能够正确连接到 Seata Server。
seata:registry:# 定义了Seata Server的注册中心配置,微服务根据配置信息去注册中心获取TC服务地址type:nacos# 指定注册中心的类型(此处使用Nacos,与微服务注册中心一致)nacos:server-addr:127.0.0.1:8848# Nacos服务器地址,与微服务注册的Nacos地址一致application:seata-server# Seata Server在Nacos中的应用名称group:SEATA_GROUP# Seata Server在Nacos中的分组名称tx-service-group:default_tx_group# 定义事务服务组的名称,用于分组管理TC和微服务service:vgroup-mapping:default_tx_group:default# 事务服务组到Seata Server集群的映射关系,default为Seata Server默认集群名称- 入口方法加注解:在发起全局事务的入口方法(如下单接口的 create 方法)上,添加 Seata 提供的
@GlobalTransactional注解,该注解用于标记全局事务的入口,Seata 会自动拦截该方法,开启全局事务,并协调各个分支事务的执行。
六、Seata 四大事务模式深度解析
Seata 作为一站式分布式事务解决方案,提供了四种事务模式,分别适配不同的业务场景,开发者可以根据自身业务的一致性要求、性能需求、开发成本等因素,选择合适的事务模式。下面我们逐一深度解析每种模式的原理、使用方法和优缺点。
6.1 XA 模式
原理
XA 模式是 Seata 从 1.2 版本开始支持的事务模式,它完全遵循 X/Open DTP 标准和 XA 协议,基于数据库原生的 XA 协议 + 两阶段提交(2PC)机制实现,核心目标是保证分布式事务的强一致性,适用于对数据一致性要求极高的场景(如金融、银行)。
Seata XA 模式的执行流程与传统 2PC 基本一致,具体如下:
一阶段:事务协调者(TC)生成全局事务 ID(XID),并分发给各个资源管理器(RM);RM 收到业务操作请求后,执行本地事务 SQL,但不提交事务,同时持有数据库锁,记录 redo/undo 日志,向 TC 报告分支事务执行状态。
二阶段:TC 收集所有 RM 的分支事务执行状态,若所有 RM 都执行成功,则向所有 RM 发送 commit 请求,RM 收到请求后正式提交事务、释放锁和资源;若有任一 RM 执行失败,则向所有 RM 发送 rollback 请求,RM 收到请求后回滚事务、释放锁和资源。
优缺点
优点:强一致,严格遵循 ACID 特性,能够保证分布式事务的原子性和一致性;无代码侵入,无需修改业务代码,只需进行简单的配置,依赖数据库原生 XA 协议实现,开发成本低。
缺点:性能较差,一阶段需要锁定数据库资源,直到二阶段结束才释放,锁定周期长,会影响系统的并发性能;依赖数据库对 XA 协议的支持,对于非关系型数据库(如 Redis)或不支持 XA 协议的关系型数据库,无法使用;存在 2PC 固有的阻塞问题和数据不一致风险。
使用
Seata XA 模式的使用非常简单,只需完成以下两步配置,无需修改业务代码:
seata:data-source-proxy-mode:XA# 配置Seata事务模式为XA@GlobalTransactional# 标记全局事务入口publicLongcreateOrder(OrderInfoorderInfo){// 1. 插入订单(订单服务本地事务)orderMapper.insert(orderInfo);// 2. 调用库存服务扣减库存(分支事务)storageApi.deduct(orderInfo.getCommodityCode(),orderInfo.getCount());// 3. 调用账户服务扣减余额(分支事务)accountApi.deduct(orderInfo.getUserId(),orderInfo.getMoney());returnorderInfo.getId();}6.2 AT 模式(Seata 主推)
核心原理
AT 模式是 Seata 创新的一种非侵入式分布式事务解决方案,也是 Seata 主推的模式,适用于绝大多数微服务业务场景。它基于两阶段提交思想进行优化,通过 Seata 自带的数据源代理(DataSourceProxy),在不修改业务代码的前提下,实现分布式事务的最终一致性,同时兼顾性能和易用性。
AT 模式的核心优势是无侵入、最终一致性、高性能,其执行流程分为两个阶段,与传统 2PC 有明显区别:
一阶段:RM 接收业务请求后,Seata 数据源代理会拦截 SQL 操作,先解析 SQL 语句,记录数据更新前的快照(前镜像)和更新后的快照(后镜像),并将这些快照信息写入 undo_log 日志表;然后执行业务 SQL,直接提交本地事务,释放本地锁和数据库连接资源;最后向 TC 注册分支事务,并报告分支事务执行状态。
二阶段:
提交:如果所有分支事务都执行成功,TC 会通知所有 RM 进行提交,RM 收到请求后,异步删除 undo_log 日志表中的相关记录,完成分布式事务的提交,这个过程非常快速,几乎不影响性能。
回滚:如果有任一分支事务执行失败,TC 会通知所有 RM 进行回滚,RM 收到请求后,根据 undo_log 日志表中的前镜像和后镜像,生成反向补偿 SQL,执行反向操作,将数据恢复到事务执行前的状态,完成分支事务的回滚。
读写隔离
AT 模式为了保证数据一致性,解决并发场景下的数据冲突问题,提供了完善的读写隔离机制,分为写隔离和读隔离:
写隔离:通过引入全局锁机制,避免多线程并发操作同一数据时出现脏写问题。具体逻辑是:一阶段本地事务提交前,RM 必须先获取该数据的全局锁,只有拿到全局锁才能提交本地事务;如果拿不到全局锁,则会重试,超时后回滚本地事务、释放本地锁,确保同一时刻只有一个全局事务能够修改该数据。
读隔离:在数据库本地事务隔离级别为“读已提交(Read Committed)”或以上的基础上,Seata AT 模式的默认全局隔离级别是“读未提交(Read Uncommitted)”,能够满足大多数业务场景的需求。如果应用在特定场景下必须要求全局“读已提交”,可以通过使用
SELECT FOR UPDATE语句实现,该语句会申请全局锁,等待全局锁释放后再执行查询,确保读取到的数据是已提交的。
使用步骤
Seata AT 模式的使用需要完成三步操作,相比 XA 模式多了一步创建 undo_log 表的操作,具体如下:
- 建 undo_log 表:undo_log 表是 AT 模式实现回滚的核心,用于存储数据的前后镜像和事务相关信息,需要在每个微服务对应的数据库中创建该表,建表 SQL 如下(适用于 MySQL 数据库)。
CREATETABLE`undo_log`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`branch_id`bigint(20)NOTNULL,`xid`varchar(100)NOTNULL,`context`varchar(128)NOTNULL,`rollback_info`longblobNOTNULL,`log_status`int(11)NOTNULL,`log_created`datetimeNOTNULL,`log_modified`datetimeNOTNULL,`ext`varchar(100)DEFAULTNULL,PRIMARYKEY(`id`),UNIQUEKEY`ux_undo_log`(`xid`,`branch_id`)-- 0.3.0+版本新增唯一索引,避免重复日志)ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8;- 配置 AT 模式:在微服务的 application.yml 配置文件中,将 Seata 事务模式配置为 AT,与 XA 模式的配置方式类似。
seata:data-source-proxy-mode:AT# 配置Seata事务模式为AT- 加
@GlobalTransactional注解:在全局事务的入口方法上添加该注解,与 XA 模式的使用方式一致,无需修改其他业务代码。
AT vs XA
为了让大家更清晰地对比两种无侵入模式的差异,下面通过表格总结两者的核心区别:
| 对比项 | AT | XA |
|---|---|---|
| 一致性 | 最终一致 | 强一致 |
| 性能 | 高,一阶段提交本地事务,释放资源快 | 低,一阶段持有锁,资源锁定久 |
| 侵入 | 无,仅需创建 undo_log 表 | 无,无需额外建表 |
| 依赖 | 通用关系型数据库,无需支持 XA 协议 | 支持 XA 协议的关系型数据库 |
6.3 TCC 模式
原理
Seata TCC 模式完全遵循 TCC 事务的核心思想,是一种业务层的分布式事务解决方案,不依赖数据库的原生事务,也不依赖 XA 协议,而是通过开发者手动编写 Try、Confirm、Cancel 三个阶段的业务逻辑,实现分布式事务的最终一致性。
Seata TCC 模式的核心原理与通用 TCC 一致,重点在于 Seata 提供了 TCC 事务协调能力,能够管理三个阶段的执行顺序,处理异常情况(如超时、重试),并通过 TCC Fence 机制解决 TCC 固有的三大问题,具体流程如下:
Try 阶段:业务服务调用 Try 方法,完成资源检查(如余额是否充足、库存是否足够)和资源预留(如冻结余额、冻结库存),确保后续 Confirm 或 Cancel 操作能够正常执行,Try 方法执行成功后,向 TC 报告分支事务状态。
Confirm 阶段:如果所有分支事务的 Try 方法都执行成功,TC 通知所有业务服务执行 Confirm 方法,Confirm 方法正式执行业务操作,使用 Try 阶段预留的资源,该方法是幂等的,确保重复执行不会出现业务异常。
Cancel 阶段:如果有任一分支事务的 Try 方法执行失败,TC 通知所有业务服务执行 Cancel 方法,Cancel 方法回滚 Try 阶段的操作,释放预留的资源,该方法也是幂等的,确保重复回滚不会出现业务异常。
三大问题与解决方案
TCC 事务在实际应用中,会遇到三个典型问题,Seata 1.5.1 及以上版本提供了 TCC Fence(栅栏)机制,通过创建 tcc_fence_log 表,自动解决这些问题,无需开发者手动处理:
空回滚:指未执行 Try 方法,却执行了 Cancel 方法。Seata TCC Fence 通过记录事务执行状态,判断 Try 方法是否执行,若未执行,则直接返回成功,避免空回滚导致的业务异常。
悬挂:指 Cancel 方法比 Try 方法先执行。Seata TCC Fence 通过全局事务 ID(XID)和分支事务 ID(Branch ID),确保 Try 方法执行前,Cancel 方法不会生效,避免悬挂导致的资源错误。
幂等:指 Try、Confirm、Cancel 方法被重复调用。Seata TCC Fence 通过记录已执行的方法,确保重复调用时不会重复执行业务逻辑,保证方法的幂等性。
使用 TCC Fence 机制时,只需在数据库中创建 tcc_fence_log 表,并在 TCC 接口上添加相关注解即可,Seata 会自动处理上述三大问题。
代码实现
Seata TCC 模式需要开发者手动编写 Try、Confirm、Cancel 三个方法,通过注解标记三个阶段的方法,具体代码示例如下(以库存扣减为例):
@LocalTCC// 标记该接口为TCC接口publicinterfaceStorageTccService{/** * Try阶段:冻结库存 * @param commodityCode 商品编码 * @param count 扣减数量 */@TwoPhaseBusinessAction(name="deduct",// 事务名称,需唯一commitMethod="confirm",// Confirm阶段方法名rollbackMethod="cancel",// Cancel阶段方法名useTCCFence=true// 开启TCC Fence机制,解决三大问题)voiddeduct(StringcommodityCode,Integercount);/** * Confirm阶段:正式扣减库存 * @param ctx 事务上下文,包含XID、Branch ID等信息 * @return 执行结果 */booleanconfirm(BusinessActionContextctx);/** * Cancel阶段:解冻库存 * @param ctx 事务上下文 * @return 执行结果 */booleancancel(BusinessActionContextctx);}优缺点
优点:性能极高,无需锁定数据库资源,资源预留后可快速释放,并发性能优于 XA 和 AT 模式;跨数据源,支持关系型数据库、非关系型数据库(如 Redis),甚至支持第三方接口,适用场景灵活;自定义程度高,开发者可以根据业务需求灵活设计 Try、Confirm、Cancel 逻辑,适配复杂业务场景。
缺点:开发量大,需要手动编写三个阶段的业务逻辑,且要保证方法的幂等性,开发难度和维护成本高;业务侵入性强,TCC 逻辑与业务逻辑深度耦合,后续业务变更时,需要同步修改 TCC 相关方法。
6.4 SAGA 模式
SAGA 模式是 Seata 提供的长事务解决方案,主要适用于业务流程长、涉及多个第三方服务、无法使用数据库事务的场景(如电商的下单-支付-发货-退款流程、供应链管理流程等)。
SAGA 模式的核心思想是“拆分长事务为短事务”,每个短事务对应一个业务步骤,直接提交本地事务,无需等待其他事务执行,当某个短事务执行失败时,通过执行反向补偿操作,回滚所有已执行的短事务,最终实现数据的最终一致性。
正常执行流程:将长事务拆分为多个子事务(短事务),每个子事务独立执行并提交本地事务,所有子事务依次执行完成,整个分布式事务执行成功。
异常回滚流程:当某个子事务执行失败时,按照相反的顺序,执行每个已成功子事务的补偿方法,回滚子事务的执行结果,直到所有子事务都回滚完成,确保数据一致性。
Seata SAGA 模式支持两种实现方式:注解式(简单场景)和编排式(复杂流程),开发者可以根据业务流程的复杂度选择合适的实现方式。
优点:无锁设计,每个子事务直接提交,不锁定资源,高吞吐、高性能,适合长事务场景;支持第三方服务和非关系型数据库,适用场景广泛;无需依赖数据库事务,灵活性高。缺点:无隔离性,多个并发 SAGA 事务操作同一数据时,可能出现数据冲突;需要为每个子事务编写对应的补偿方法,开发和维护成本高;补偿方法的编写难度大,需要考虑各种异常场景,确保补偿逻辑的正确性。
七、Seata 四种模式选型对比
为了帮助大家在实际项目中快速选择合适的 Seata 事务模式,下面通过表格,从一致性、性能、侵入性、适用场景四个核心维度,对四种模式进行全面对比:
| 模式 | 一致性 | 性能 | 侵入 | 适用场景 |
|---|---|---|---|---|
| XA | 强一致 | 差 | 无 | 金融、银行、支付等对数据一致性要求极高的场景 |
| AT | 最终一致 | 好 | 无 | 90% 微服务业务场景,如电商下单、订单管理等,关系型数据库优先 |
| TCC | 最终一致 | 极高 | 高 | 高性能需求、跨数据源(如 MySQL+Redis)、自定义锁场景 |
| SAGA | 最终一致 | 高 | 高 | 长事务、涉及第三方服务、遗留系统集成场景 |
最佳实践:在实际项目中,无需盲目追求强一致性,应根据业务需求选择合适的模式,优先保证系统的可用性和性能:
普通业务场景(如电商下单、用户注册),优先选择AT 模式,兼顾易用性和性能。
金融、银行等对数据一致性要求极高的场景,选择XA 模式,牺牲部分性能换取强一致性。
高性能、高并发,且涉及跨数据源(如 MySQL+Redis)的场景,选择TCC 模式,灵活适配业务需求。
业务流程长、涉及第三方服务或遗留系统的场景,选择SAGA 模式,解决长事务问题。
八、总结
分布式事务是微服务架构落地过程中不可回避的核心难题,它直接影响系统的数据