文章目录
1. Seata事务模型概述
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的分布式事务解决方案,提供AT(自动补偿)、TCC(Try-Confirm-Cancel)、SAGA和XA四种事务模式。其中AT模式是最常用的自动补偿型事务实现。
1.1 核心组件角色
组件 | 职责描述 |
---|---|
TC (Transaction Coordinator) | 事务协调器,维护全局事务和分支事务状态,驱动全局提交或回滚 |
TM (Transaction Manager) | 事务管理器,定义全局事务边界,负责开启/提交/回滚全局事务 |
RM (Resource Manager) | 资源管理器,管理分支事务,负责分支注册、状态汇报和本地事务的提交/回滚 |
2. AT模式回滚实现原理
2.1 核心机制:二阶段提交+反向补偿
Seata AT模式通过两阶段提交实现事务控制:
- 第一阶段:执行业务SQL并生成回滚日志(Undo Log)
- 第二阶段:
- 成功则异步删除日志
- 失败则通过回滚日志进行补偿
2.2 关键数据结构:Undo Log
Undo Log是AT模式实现回滚的核心,其JSON结构示例:
{
"branchId": 641789253,
"xid": "192.168.1.1:8091:641789252",
"context": {
"undoItems": [{
"afterImage": {
"rows": [{
"fields": [
{"name": "id", "type": 4, "value": 1},
{"name": "name", "type": 12, "value": "旧值"}
]
}],
"tableName": "product"
},
"beforeImage": {
"rows": [{
"fields": [
{"name": "id", "type": 4, "value": 1},
{"name": "name", "type": 12, "value": "新值"}
]
}],
"tableName": "product"
},
"sqlType": "UPDATE"
}],
"transactionMode": "AT"
},
"logCreated": 1638432000000,
"logStatus": "Normal"
}
3. 回滚流程详细解析
3.1 正常回滚流程
-
触发条件:
- 业务代码抛出异常
- TM发起全局回滚
- 事务超时
-
执行步骤:
// 典型的事务回滚触发代码
@GlobalTransactional
public void purchase(String userId, String commodityCode, int count) {
storageService.deduct(commodityCode, count); // 扣减库存
if(accountService.debit(userId, money)) { // 扣款
throw new RuntimeException("人工触发回滚");
}
orderService.create(userId, commodityCode, count); // 创建订单
}
- 回滚时序:
3.2 回滚失败处理机制
-
重试策略:
- 默认重试3次(可配置)
- 指数退避间隔(1s, 3s, 5s)
-
人工干预:
-- 查询悬挂事务 SELECT * FROM undo_log WHERE xid = '192.168.1.1:8091:641789252'; -- 手动删除日志(谨慎操作) DELETE FROM undo_log WHERE xid = '192.168.1.1:8091:641789252';
-
配置参数:
# 最大重试次数 client.undo.log.table=undo_log client.rm.lock.retry.times=3 client.rm.lock.retry.interval=1000
4. 关键技术实现细节
4.1 SQL拦截与解析
Seata通过JDBC代理拦截SQL执行:
public class ExecuteTemplate {
public static <T, S extends Statement> T execute(...) throws SQLException {
// 前置处理:解析SQL类型
SQLRecognizer recognizer = SQLVisitorFactory.get(sql, dbType);
// 执行前镜像查询(SELECT)
TableRecords beforeImage = executor.beforeImage();
// 执行业务SQL
T result = statementCallback.execute(statement, args);
// 执行后镜像查询(SELECT)
TableRecords afterImage = executor.afterImage();
// 生成Undo Log
UndoLogManager.saveUndoLog(xid, branchId, beforeImage, afterImage);
}
}
4.2 全局锁机制
为防止脏写,Seata实现了全局锁:
public class DefaultLockManagerImpl implements LockManager {
public boolean acquireLock(BranchSession branchSession) {
List<RowLock> locks = collectRowLocks(branchSession);
return LockerFactory.getLock(lockMode).acquireLock(locks);
}
}
锁存储结构(TC端):
CREATE TABLE IF NOT EXISTS `lock_table` (
`row_key` varchar(128) NOT NULL,
`xid` varchar(96) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`branch_id` bigint(20) NOT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`table_name` varchar(32) DEFAULT NULL,
`pk` varchar(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
);
5. 不同场景下的回滚行为
5.1 新增数据回滚
-- 原始SQL
INSERT INTO orders(id, user_id, amount) VALUES(1, 'U1001', 100);
-- 回滚SQL
DELETE FROM orders WHERE id = 1;
5.2 更新数据回滚
-- 原始SQL
UPDATE account SET balance = balance - 100 WHERE user_id = 'U1001';
-- 回滚SQL
UPDATE account SET balance = balance + 100 WHERE user_id = 'U1001';
5.3 删除数据回滚
-- 原始SQL
DELETE FROM inventory WHERE product_id = 'P1001';
-- 回滚SQL
-- 根据beforeImage恢复数据
INSERT INTO inventory(product_id, stock) VALUES('P1001', 50);
6. 生产环境最佳实践
6.1 性能优化配置
# Undo Log配置
client.undo.log.save.days=7
client.undo.log.delete.period=86400000
# 异步线程池配置
client.async.commit.buffer.limit=10000
client.undo.log.asyn.buffer.size=1000
6.2 高可用部署方案
6.3 异常处理建议
-
空回滚处理:
@Override public boolean commit(BranchSession branchSession) { // 检查业务数据是否存在 if(!checkDataExists(branchSession.getXid())) { LOG.warn("空回滚,跳过处理"); return true; } // 正常提交逻辑 }
-
防悬挂措施:
@GlobalTransactional public void businessMethod() { try { // 业务逻辑 } catch(Exception e) { // 确保异常能传播到TM throw e; } }
7. 与其他模式对比
特性 | AT模式 | TCC模式 | SAGA模式 |
---|---|---|---|
回滚机制 | 自动生成反向SQL | 手动编写Cancel逻辑 | 手动编写补偿事务 |
侵入性 | 低(无代码侵入) | 高(需实现3个接口) | 中(需定义补偿流程) |
性能影响 | 中(需写Undo Log) | 高(两阶段预留资源) | 低(最终一致性) |
适用场景 | 常规CRUD操作 | 高一致性要求场景 | 长事务流程 |
锁粒度 | 行级锁 | 业务资源锁 | 无锁 |
8. 常见问题解决方案
8.1 回滚失败排查步骤
-
检查TC日志:
grep "exception" logs/seata.log
-
查询事务状态:
SELECT * FROM global_table WHERE xid = 'xxx'; SELECT * FROM branch_table WHERE xid = 'xxx';
-
验证Undo Log:
SELECT * FROM undo_log WHERE xid = 'xxx' FOR UPDATE;
8.2 跨服务调用问题
解决方案:
-
确保XID传播:
@Bean public FeignInterceptor seataFeignInterceptor() { return new FeignInterceptor(); }
-
配置超时时间:
# RPC调用超时应小于事务超时 client.rm.report.retry.count=5 client.tm.commit.retry.count=3
8.3 数据源代理冲突
正确配置:
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary
@Bean("dataSource")
public DataSource dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
9. 演进方向与替代方案
-
Seata 2.0改进:
- 支持Redis存储Undo Log
- 增强SAGA状态机
- 云原生集成
-
Service Mesh方案:
# Istio VirtualService示例 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: payments spec: hosts: - payments http: - route: - destination: host: payments subset: v1 retries: attempts: 3 retryOn: 5xx,gateway-error
-
消息事务方案:
// RocketMQ事务消息示例 TransactionMQProducer producer = new TransactionMQProducer("group"); producer.setTransactionListener(new LocalTransactionListener() { @Override public LocalTransactionState executeLocalTransaction(Message msg, Object arg) { // 执行本地事务 return LocalTransactionState.COMMIT_MESSAGE; } @Override public LocalTransactionState checkLocalTransaction(MessageExt msg) { // 检查本地事务状态 return LocalTransactionState.COMMIT_MESSAGE; } });
10. 总结建议
-
模式选择原则:
- 简单CRUD:优先AT模式
- 跨系统集成:考虑TCC/SAGA
- 金融支付:推荐TCC
-
性能关键点:
- Undo Log表单独部署
- 合理设置事务超时时间
- 避免大事务
-
监控指标:
- 事务成功率/失败率
- 平均处理时间
- Undo Log积压量
Seata的回滚机制通过精巧的Undo Log设计和两阶段协议实现,在保证数据一致性的同时提供了较好的易用性。实际应用中需要根据业务特点合理配置,并建立完善的监控体系,才能充分发挥其价值。