Seata中分布式事务的解决方案
约 2551 字大约 9 分钟
2025-09-02
本篇文章主要介绍下Seata中的分布式事务解决方案。
Seata介绍
Seata全称是Simple Extension Autonomous Transaction Architecture,它的意思是简单可扩展的自治事务框架,是阿里爸爸开源的分布式事务解决方案,旨在解决微服务构架下跨服务、跨数据库的事务一致性问题。它通过提供全局事务管理,分支事务协调等功能,帮助开发者无需修改业务代码即可实现分布式事务的原子性、一致性、隔离性和持久性。
基础概念
核心结构
Seata采用三组件协同架构,各组件分工明确,共同完成分布式事务管理。
TC(Transaction Coordinator,事务协调器)
独立部署的中间件,是Seata的大脑。负责维护全局事务状态(如创建、提交、回滚),存储事务日志(支持Redis、DB、File等存储模式),并协调RM执行分支事务的提交或回滚。
TM(Transaction Manager,事务管理器)
嵌入在业务服务中的客户端组件,是事务的发起者。负责定义全局事务的边界(通过@GlobalTransaction注解),向TC注册全局事务,并根据TC的决策发起提交或回滚指令;
RM(Resource Manage,资源管理器)
嵌入在业务服务中的客户端组件,是分支事务的执行者。负责管理本地资源(如数据库连接),向TC注册分支事务,执行TC下发的提交或回滚指令,并生成回滚日志(用于故障恢复)。
事务分组
事务分组:事务分组时Seata的资源逻辑,可以按照微服务的需要,在应用程序(客户端)对自行定义事务分组,每组取一个名字。
集群:seata-server服务端的一个或多个节点组成的集群cluster。应用程序(客户端)使用时需要指定事务逻辑分组与Seata服务端集群的映射关系。
事务分组与后端Seata集群之间的映射关系
- 首先应用程序使用
seata.tx-service-group配置来指明当前应用使用的事务分组; - 应用程序(客户端)会通过用户配置的配置中心去寻找
service.vgroupMapping.[事务分组配置项],取得配置项的值就是TC集群的名称。如果是SpringBoot应用,则可以通过seata.service.vgroup-mapping.事务分组=集群名称来进行配置; - 拿到集群名称程序通过一定的前后缀+集群名称去构造服务名,各配置中心的服务名实现不同。(前提是Seata-Server已经完成了服务注册,且Seata-Server向注册中心报告cluster名与各应用程序配置的集群名称一致)
- 拿到服务名去相应的注册中心去拉取相应服务名的服务列表,获得后端真实的TC服务列表;
不同部署模式下的事务分组的使用案例(以SpringBoot应用为例子)
内置File
服务端的/seata-server/application.yml文件的内容为:
# Copyright 1999-2019 Seata.io Group.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${log.home:${user.home}/logs/seata}
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
console:
user:
username: seata
password: seata
seata:
config:
# 核心配置为file
type: file
registry:
# 核心配置为file
type: file
store:
# 核心配置为file
mode: file此时在客户端需要进行的配置为:
seata:
enable: true,
application-id: ${spring.application.name}
tx-service-group: xa_order_group
data-source-proxy-mode: XA # 数据源使用XA模式
service:
vgroup-mapping:
xa_order_group: default
group-list:
default: 124.222.91.208:8091
registry:
type: file
config:
type: file第三方配置中心以Nacos为例子
当我们采用Nacos作为注册中心,MySQL作为持久化存储的时候。服务端的配置内容如下:
server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
console:
user:
username: seata
password: seata
seata:
config:
# support: nacos, consul, apollo, zk, etcd3
type: nacos
nacos:
server-addr: nacos_ip:nacos_port
namespace: seata-server
group: SEATA_GROUP
username: nacos
password: nacos
data-id: seataServer.properties
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: nacos_ip:nacos_port
group: SEATA_GROUP
namespace: seata-server
# tc集群名称
cluster: default
username: nacos
password: nacos
# server:
# service-port: 8091 #If not configured, the default is '${server.port} + 1000'
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login然后还需要再nacos创建一个(namespace=seata-server,group=SEATA_GROUP,data-id=seataServer.properties)的配置项,其中存储的是Seata存储的相关配置内容:
store.mode=db
#-----db-----
store.db.datasource=druid
store.db.dbType=mysql
# 需要根据mysql的版本调整driverClassName
# mysql8及以上版本对应的driver:com.mysql.cj.jdbc.Driver
# mysql8以下版本的driver:com.mysql.jdbc.Driver
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata-server?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
store.db.user= 用户名
store.db.password=密码
# 数据库初始连接数
store.db.minConn=1
# 数据库最大连接数
store.db.maxConn=20
# 获取连接时最大等待时间 默认5000,单位毫秒
store.db.maxWait=5000
# 全局事务表名 默认global_table
store.db.globalTable=global_table
# 分支事务表名 默认branch_table
store.db.branchTable=branch_table
# 全局锁表名 默认lock_table
store.db.lockTable=lock_table
# 查询全局事务一次的最大条数 默认100
store.db.queryLimit=100
# undo保留天数 默认7天,log_status=1(附录3)和未正常清理的undo
server.undo.logSaveDays=7
# undo清理线程间隔时间 默认86400000,单位毫秒
server.undo.logDeletePeriod=86400000
# 二阶段提交重试超时时长 单位ms,s,m,h,d,对应毫秒,秒,分,小时,天,默认毫秒。默认值-1表示无限重试
# 公式: timeout>=now-globalTransactionBeginTime,true表示超时则不再重试
# 注: 达到超时时间后将不会做任何重试,有数据不一致风险,除非业务自行可校准数据,否者慎用
server.maxCommitRetryTimeout=-1
# 二阶段回滚重试超时时长
server.maxRollbackRetryTimeout=-1
# 二阶段提交未完成状态全局事务重试提交线程间隔时间 默认1000,单位毫秒
server.recovery.committingRetryPeriod=1000
# 二阶段异步提交状态重试提交线程间隔时间 默认1000,单位毫秒
server.recovery.asynCommittingRetryPeriod=1000
# 二阶段回滚状态重试回滚线程间隔时间 默认1000,单位毫秒
server.recovery.rollbackingRetryPeriod=1000
# 超时状态检测重试线程间隔时间 默认1000,单位毫秒,检测出超时将全局事务置入回滚会话管理器
server.recovery.timeoutRetryPeriod=1000修改它的配置指向需要的MySQL的地址即可。
往上服务端配置就已经完成,接着是客户端的配置。在客户端我们需要通过事务分组找到Seata-Server的位置:
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: xa_order_group
service:
grouplist:
default: 192.168.128.2:8091
vgroup-mapping:
xa_order_group: default
registry:
type: nacos
nacos:
namespace: seata-server
group: SEATA_GROUP
server-addr: 192.168.128.2:8848
config:
type: nacos
nacos:
namespace: seata-server
group: SEATA_GROUP
server-addr: 192.168.128.2:8848
data-id: seataServer.properties因为客户端会根据service.vgroupMapping.xa_order_group作为data-id,在seata-server命名空间,SEATA_GROUP分组下寻找对应的配置文件,它获取的内容就是集群的名称。
提示
在Nacos上创建配置文件的时候注意,它会获取文件中所有的内容作为集群的名字,所以最好的办法是将Nacos上的配置文件的类型设置为Text,然后里面的内容就是集群的名称即可。
然后他会根据获取到的集群名称,在seata.service.grouplist配置项中根据集群的名称获取到Seata-Server的连接信息。
Seata的事务模式
Seata支持多种事务模式,覆盖不同业务场景的需求。
AT模式(自动补偿模式)
Seata的默认模式,适用于大多数的CRUD场景。核心原理是通过SQL解析+反向补偿实现无侵入性。
一阶段执行业务SQL时,自动生成回滚日志(记录数据前后的镜像)并提交本地事务;
二阶段根据全局事务结果,通过回滚日志自动恢复数据(提交时删除日志,回滚时执行反向SQL);
优点是零业务侵入、高性能,缺点是需要数据库支持ACID;
TCC模式(Try-Confirm-Cancel模式)
适用于复杂业务逻辑(如涉及到非数据库操作、需要精细化控制事务边界)。分为三个阶段:Try(预留资源,如冻结库存)、Confirm(确认提交,如扣减冻结库存)和Cancel(取消操作,如释放冻结库存)。
优点是灵活性高,缺点是需要手动实现三个阶段,开发成本高;
Saga模式(长事务补偿模式)
适用于跨多服务的长时间事务(如订单状态机,异步操作)。将大事务拆分成多个本地事务,按顺序执行;若某一步失败,反向执行所有已成功的步骤的补偿操作
优点是适用于长流程,缺点是性能较低、锁定资源时间长。
XA模式(两阶段提交模式)
适用于强一致性要求的场景(如金融交易)。基于XA协议,一阶段RM执行本地事务但不提交(处于Prepare状态),二阶段根据所有RM的Prepare结果决定全局提交或回滚。
优点是强一致性,缺点是性能较低、锁定资源时间长。
核心特点
- 高兼容性:支持主流开发框架(Spring Boot、Spring Cloud、Dubbo),兼容MySQL、PostgreSQL、Oracle等多种数据库;
- 高性能:AT模式通过异步化处理和批量清理回滚日志,单事务链路耗时<100ms,比传统2PC性能提升10倍以上;
- 高可用性:支持TC集群部署(基于数据库或Redis存储事务日志),故障自动转移,确保事务协调不中断;
- 多模式支持:一套框架覆盖AT、TCC、Saga、XA等多种事务模式,适应不同业务场景的需求。