Seata 核心概念
什么是分布式事务
分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的节点之上。
分布式事务问题
┌─────────────┐ ┌─────────────┐
│ 服务 A │ │ 服务 B │
│ (订单服务) │─────>│ (库存服务) │
│ │ │ │
│ 创建订单 │ │ 扣减库存 │
│ ✅ 成功 │ │ ❌ 失败 │
└─────────────┘ └─────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ 数据库 A │ │ 数据库 B │
│ 订单已创建 │ │ 库存未扣减 │ ← 数据不一致!
└─────────────┘ └─────────────┘
CAP 理论
- 一致性(Consistency):所有节点在同一时间具有相同的数据
- 可用性(Availability):保证每个请求不管成功或者失败都有响应
- 分区容错性(Partition tolerance):系统中任意信息的丢失或失败不会影响系统的继续运作
BASE 理论:
- 基本可用(Basically Available)
- 软状态(Soft state)
- 最终一致性(Eventually consistent)
Seata 简介
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的一站式分布式事务解决方案。
核心特性
- 支持多种事务模式:AT、TCC、Saga、XA
- 高性能:AT 模式性能接近本地事务
- 低侵入:AT 模式无需修改业务代码
- 易部署:支持多种部署方式
- 多语言支持:支持 Java、Go、Python 等
三大角色
┌─────────────────────────────────────────────────────┐
│ Transaction Coordinator (TC) │
│ 事务协调器,维护全局事务状态 │
└───────────────────────┬─────────────────────────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Transaction │ │ Transaction │ │ Transaction │
│ Manager (TM) │ │ Resource │ │ Resource │
│ 事务管理器 │ │ Manager (RM) │ │ Manager (RM) │
│ │ │ 资源管理器 │ │ 资源管理器 │
│ - 定义事务边界│ │ - 管理资源 │ │ - 管理资源 │
│ - 发起事务 │ │ - 注册分支 │ │ - 注册分支 │
└──────────────┘ └──────────────┘ └──────────────┘
全局事务 分支事务 1 分支事务 2
- TC(Transaction Coordinator):事务协调器,维护全局和分支事务状态
- TM(Transaction Manager):事务管理器,定义事务边界,发起事务
- RM(Resource Manager):资源管理器,管理资源,处理分支事务
全局事务流程
1. TM 向 TC 申请开启全局事务
2. TC 生成全局事务 ID(XID)
3. TM 将 XID 传递给业务服务
4. RM 向 TC 注册分支事务
5. TM 向 TC 提交或回滚全局事务
6. TC 协调所有分支事务提交或回滚
事务模式
1. AT 模式(Auto Transaction)
特点:
- 无侵入,无需修改业务代码
- 基于本地事务 + 两阶段提交
- 高性能,性能接近本地事务
- 需要支持本地事务的关系型数据库
工作原理:
阶段一(Prepare):
1. 执行 SQL 并记录前镜像和后镜像
2. 提交本地事务
3. 释放本地锁
阶段二(Commit/Rollback):
- Commit:异步删除 undo_log
- Rollback:根据 undo_log 补偿数据
适用场景:
- 对性能要求高
- 数据库支持本地事务
- 业务代码不想修改
2. TCC 模式(Try-Confirm-Cancel)
特点:
- 高性能,资源隔离性好
- 需要实现三个接口
- 无数据库依赖
- 可能存在空回滚、悬挂等问题
工作原理:
Try 阶段:
- 检查和预留资源
- 不执行业务操作
Confirm 阶段:
- 执行业务操作
- 使用 Try 阶段预留的资源
Cancel 阶段:
- 释放 Try 阶段预留的资源
代码示例:
@LocalTCC
public interface TccTransactionService {
@TCCBusinessActionName("tccAction")
@TCCBusinessAction(methodName = "tryMethod",
commitMethod = "confirmMethod",
rollbackMethod = "cancelMethod")
boolean tryMethod(TccParam param);
boolean confirmMethod(TccParam param);
boolean cancelMethod(TccParam param);
}
适用场景:
- 对性能要求高
- 需要资源隔离
- 可以接受代码侵入
3. Saga 模式
特点:
- 长事务解决方案
- 每个参与者都有补偿操作
- 最终一致性
- 可能存在脏读、写偏斜
工作原理:
正向操作:Service1 → Service2 → Service3
补偿操作:Service3 补偿 → Service2 补偿 → Service1 补偿
配置示例:
{
"Name": "Saga 事务",
"Comment": "Saga 事务示例",
"Version": "1.0",
"StartState": "Service1",
"States": {
"Service1": {
"Type": "ServiceTask",
"ServiceName": "service1",
"Next": "Service2",
"CompensateState": "Service1Compensate"
},
"Service2": {
"Type": "ServiceTask",
"ServiceName": "service2",
"Next": "Service3",
"CompensateState": "Service2Compensate"
},
"Service3": {
"Type": "ServiceTask",
"ServiceName": "service3",
"End": true,
"CompensateState": "Service3Compensate"
}
}
}
适用场景:
- 长事务
- 参与者不支持悬挂
- 可以接受最终一致性
4. XA 模式
特点:
- 强一致性
- 基于数据库 XA 协议
- 性能较差
- 需要数据库支持 XA
工作原理:
阶段一(Prepare):
- 执行 SQL,不提交
- 等待 TC 指令
阶段二(Commit/Rollback):
- Commit:提交所有分支事务
- Rollback:回滚所有分支事务
适用场景:
- 对一致性要求高
- 对性能要求不高
- 数据库支持 XA 协议
快速开始
1. 部署 Seata Server
# 下载 Seata Server
wget https://github.com/seata/seata/releases/download/v1.7.0/seata-server-1.7.0.tar.gz
tar -xzf seata-server-1.7.0.tar.gz
# 配置文件(registry.conf)
cd seata/conf
vim registry.conf
registry {
type = "nacos"
nacos {
serverAddr = "localhost:8848"
namespace = "public"
group = "SEATA_GROUP"
application = "seata-server"
}
}
config {
type = "nacos"
nacos {
serverAddr = "localhost:8848"
namespace = "public"
group = "SEATA_GROUP"
dataId = "seataServer.properties"
}
}
2. 添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
3. 配置 Seata
seata:
enabled: true
tx-service-group: default_tx_group
service:
vgroup-mapping:
default_tx_group: default
grouplist:
default: 127.0.0.1:8091
registry:
type: nacos
nacos:
server-addr: localhost:8848
namespace: public
group: SEATA_GROUP
application: seata-server
config:
type: nacos
nacos:
server-addr: localhost:8848
namespace: public
group: SEATA_GROUP
data-id: seataServer.properties
4. 使用 AT 模式
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountService accountService;
@Autowired
private StorageService storageService;
@GlobalTransactional // 开启全局事务
public void createOrder(Order order) {
// 1. 创建订单
orderMapper.insert(order);
// 2. 扣减库存
storageService.decrease(order.getProductId(), order.getCount());
// 3. 扣减账户余额
accountService.decrease(order.getUserId(), order.getAmount());
}
}
5. 配置数据源
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
}
6. 创建 undo_log 表
-- MySQL
CREATE TABLE IF NOT EXISTS `undo_log` (
`branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`),
KEY `ix_log_created` (`log_created`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AT transaction mode undo table';
高可用部署
1. Seata Server 集群
# registry.conf
registry {
type = "nacos"
nacos {
serverAddr = "nacos1:8848,nacos2:8848,nacos3:8848"
namespace = "public"
group = "SEATA_GROUP"
application = "seata-server"
}
}
# file.conf
store {
mode = "db"
db {
datasource = "druid"
dbType = "mysql"
url = "jdbc:mysql://mysql1:3306/seata,mysql2:3306/seata"
user = "seata"
password = "seata"
minConn = 5
maxConn = 100
}
}
2. 数据库配置
-- 创建 seata 数据库
CREATE DATABASE seata;
-- 创建事务表
CREATE TABLE `global_table` (
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 创建分支表
CREATE TABLE `branch_table` (
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 创建锁表
CREATE TABLE `lock_table` (
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(96),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
最佳实践
1. 事务粒度
- 小事务原则:事务范围尽可能小
- 避免长事务:减少事务持有时间
- 避免跨服务大事务:尽量在单服务内完成
2. 性能优化
- 使用 AT 模式:性能最优
- 异步提交:阶段二异步提交
- 批量提交:减少网络往返
3. 异常处理
@GlobalTransactional
public void createOrder(Order order) {
try {
// 业务逻辑
orderMapper.insert(order);
storageService.decrease(order.getProductId(), order.getCount());
accountService.decrease(order.getUserId(), order.getAmount());
} catch (BusinessException e) {
// 业务异常,抛出异常触发回滚
throw e;
} catch (Exception e) {
// 系统异常,记录日志并抛出
log.error("创建订单失败", e);
throw new SystemException("系统异常", e);
}
}
4. 监控告警
@Component
public class SeataMonitor {
@Autowired
private AlertService alertService;
@EventListener
public void onTransactionEvent(TransactionEvent event) {
if (event.getStatus() == TransactionStatus.Rollbacked) {
alertService.sendAlert("事务回滚:" + event.getXid());
}
}
}
常见问题
1. 事务不生效
问题:@GlobalTransactional 注解不生效
排查步骤:
- 检查是否启用 Seata
- 检查数据源配置
- 检查 undo_log 表是否存在
- 查看 Seata 日志
2. 性能问题
问题:使用 Seata 后性能下降
解决方案:
- 使用 AT 模式
- 优化事务粒度
- 配置异步提交
3. 数据不一致
问题:分布式事务后数据不一致
解决方案:
- 检查是否正确使用事务
- 查看 undo_log 记录
- 检查网络是否稳定
总结
Seata 提供了多种分布式事务解决方案,AT 模式无侵入且性能优异,TCC 模式适合高性能场景,Saga 模式适合长事务。
合理选择事务模式,优化事务粒度,可以有效解决分布式事务问题。
在生产环境中,建议部署 Seata Server 集群,做好监控告警,并建立完善的异常处理机制。