一、Seata核心架构与定位
Seata(Simple Extensible Autonomous Transaction Architecture)是一款由阿里巴巴开源的分布式事务解决方案,旨在为微服务架构提供高性能且易于集成的分布式事务能力。
Seata的架构演进

Seata核心角色解析
| 角色 |
简称 |
职责 |
类比 |
| 事务协调器 |
TC (Transaction Coordinator) |
维护全局和分支事务的状态,驱动全局事务的提交或回滚。 |
裁判 |
| 事务管理器 |
TM (Transaction Manager) |
定义全局事务的边界,负责开启、提交或回滚全局事务。 |
教练 |
| 资源管理器 |
RM (Resource Manager) |
管理分支事务,负责分支事务的注册、状态报告,并驱动分支事务的提交和回滚。 |
运动员 |
二、Seata四种事务模式对比
| 特性 |
AT模式 |
TCC模式 |
Saga模式 |
XA模式 |
| 原理 |
基于SQL解析的自动补偿 |
Try-Confirm-Cancel三阶段 |
状态机 + 补偿事务 |
XA两阶段提交 |
| 侵入性 |
⭐ 无侵入(代理数据源) |
⭐⭐⭐⭐ 高侵入(需实现三个接口) |
⭐⭐⭐ 中侵入(需定义状态机) |
⭐ 无侵入 |
| 性能 |
⭐⭐⭐⭐ 高 |
⭐⭐⭐⭐ 高 |
⭐⭐⭐ 中 |
⭐⭐ 低 |
| 一致性 |
最终一致性 |
强一致性 |
最终一致性 |
强一致性 |
| 适用场景 |
大部分常规业务场景 |
金融、资金交易等强一致性场景 |
长事务、跨系统业务流程 |
传统数据库事务迁移 |
三、Seata AT模式深度解析
1. AT模式工作原理
AT模式是一种两阶段提交的增强实现,其核心在于一阶段即提交本地事务,并通过Undo Log机制保证二阶段的可回滚性。

2. AT模式核心实现机制
AT模式的自动补偿能力建立在SQL拦截和镜像生成之上。
/**
* AT模式数据源代理
* 通过DataSourceProxy拦截所有SQL执行
*/
public class DataSourceProxy extends AbstractDataSourceProxy {
private final DataSource targetDataSource;
@Override
public ConnectionProxy getConnection() throws SQLException {
Connection targetConnection = targetDataSource.getConnection();
return new ConnectionProxy(this, targetConnection);
}
}
/**
* 连接代理 - 拦截所有SQL执行
*/
public class ConnectionProxy implements Connection {
private final Connection targetConnection;
private final List<SQLRecognizer> sqlRecognizers;
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
// 1. SQL解析
sqlRecognizers = SQLVisitorFactory.get(sql, dbType);
// 2. 生成前后镜像(Before & After Image)
for (SQLRecognizer recognizer : sqlRecognizers) {
switch (recognizer.getSQLType()) {
case INSERT:
TableRecords afterImage = buildTableRecords(recognizer);
break;
case UPDATE:
TableRecords beforeImage = queryBeforeImage(recognizer);
TableRecords afterImage = queryAfterImage(recognizer, beforeImage);
break;
case DELETE:
TableRecords beforeImage = queryBeforeImage(recognizer);
break;
}
}
// 3. 执行业务SQL
PreparedStatement targetPreparedStatement = targetConnection.prepareStatement(sql);
return new PreparedStatementProxy(this, targetPreparedStatement, recognizer);
}
}
/**
* Undo Log核心数据结构
*/
public class UndoLog {
private Long id;
private String xid; // 全局事务ID
private Long branchId; // 分支事务ID
private String rollbackInfo; // 序列化后的回滚信息(前后镜像)
private Integer logStatus; // 状态
private Date logCreated;
private Date logModified;
}
3. AT模式实战配置与示例
Client端配置 (application.yml)
# Seata Client 配置
seata:
enabled: true
application-id: order-service
tx-service-group: my_tx_group
enable-auto-data-source-proxy: true # 开启自动数据源代理
config:
type: nacos
nacos:
server-addr: localhost:8848
group: SEATA_GROUP
registry:
type: nacos
nacos:
application: seata-server
server-addr: localhost:8848
group: SEATA_GROUP
# 标准数据源配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/order_db
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
业务代码示例
在基于Java和SpringBoot的微服务中,通过一个注解即可开启全局事务。
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private AccountFeignClient accountClient;
@Autowired
private InventoryFeignClient inventoryClient;
/**
* 创建订单 - 分布式事务
* @GlobalTransactional 注解标记此方法为一个全局事务的起点
*/
@GlobalTransactional(name = "create-order", timeoutMills = 300000)
public void createOrder(OrderDTO orderDTO) {
log.info("======> 开始创建订单,全局事务XID: {}", RootContext.getXID());
// 阶段一:本地操作
Order order = createOrderLocal(orderDTO);
// 阶段二:远程调用 - 扣减库存
ResponseEntity<Void> inventoryResponse = inventoryClient.deduct(
orderDTO.getProductId(),
orderDTO.getQuantity()
);
if (!inventoryResponse.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("库存扣减失败,触发全局回滚");
}
// 阶段三:远程调用 - 扣减余额
ResponseEntity<Void> accountResponse = accountClient.deduct(
orderDTO.getUserId(),
orderDTO.getAmount()
);
if (!accountResponse.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("余额扣减失败,触发全局回滚");
}
// 所有操作成功,更新订单状态
updateOrderStatus(order.getId(), OrderStatus.SUCCESS);
log.info("======> 订单创建成功,全局事务提交");
}
private Order createOrderLocal(OrderDTO orderDTO) {
// ... 本地创建订单逻辑
orderMapper.insert(order);
return order;
}
}
Feign客户端配置(传递XID)
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor seataFeignInterceptor() {
return template -> {
// 将当前全局事务XID传递到下游服务
String xid = RootContext.getXID();
if (StringUtils.isNotBlank(xid)) {
template.header("TX_XID", xid);
}
};
}
}
四、TCC模式深度解析与实战
1. TCC模式实现
TCC模式要求开发者显式实现Try、Confirm、Cancel三个业务逻辑。
/**
* TCC订单服务接口
*/
public interface TccOrderService {
@TwoPhaseBusinessAction(name = "orderService", commitMethod = "confirm", rollbackMethod = "cancel")
boolean tryCreateOrder(@BusinessActionContextParameter(paramName = "order") OrderDTO order);
boolean confirm(BusinessActionContext actionContext);
boolean cancel(BusinessActionContext actionContext);
}
@Service
public class TccOrderServiceImpl implements TccOrderService {
@Autowired
private OrderMapper orderMapper;
@Override
public boolean tryCreateOrder(OrderDTO orderDTO) {
log.info("TCC Try阶段:预创建订单(资源预留)");
// 幂等性检查,防止重复执行
Order existOrder = orderMapper.selectByOrderNo(orderDTO.getOrderNo());
if (existOrder != null) {
log.warn("订单已存在,直接返回成功");
return true;
}
// 创建状态为TRY(尝试中)的订单,并设置过期时间
Order order = new Order();
order.setStatus(OrderStatus.TRY);
order.setExpireTime(DateUtils.addMinutes(new Date(), 30));
orderMapper.insert(order);
return true;
}
@Override
public boolean confirm(BusinessActionContext actionContext) {
log.info("TCC Confirm阶段:确认订单");
String orderNo = (String) actionContext.getActionContext("orderNo");
// 将订单状态从TRY更新为CONFIRMED
int result = orderMapper.updateStatusByOrderNo(orderNo, OrderStatus.TRY, OrderStatus.CONFIRMED);
return result > 0;
}
@Override
public boolean cancel(BusinessActionContext actionContext) {
log.info("TCC Cancel阶段:取消订单");
String orderNo = (String) actionContext.getActionContext("orderNo");
// 空回滚检查:如果Try没执行,直接记录空回滚并返回
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) {
recordEmptyRollback(orderNo); // 记录防悬挂
return true;
}
// 正常回滚:将订单状态从TRY更新为CANCELLED
int result = orderMapper.updateStatusByOrderNo(orderNo, OrderStatus.TRY, OrderStatus.CANCELLED);
return result > 0;
}
}
2. TCC防悬挂与空回滚解决方案
@Component
public class TccProblemSolver {
/**
* 防悬挂检查:在Try阶段执行前调用
* 若发现已存在针对该业务键的空回滚记录,则说明发生了悬挂(Cancel先于Try到达)
*/
public void checkHangingBeforeTry(String businessKey) {
if (isEmptyRollback(businessKey)) {
throw new RuntimeException("检测到悬挂风险,拒绝执行Try操作,业务键:" + businessKey);
}
}
private boolean isEmptyRollback(String businessKey) {
// 查询空回滚记录表,判断此业务键是否已执行过空回滚
return emptyRollbackMapper.existsByBusinessKey(businessKey);
}
}
五、Seata Server部署与高可用配置
1. Server端核心配置 (application.yml)
server:
port: 7091
seata:
config:
type: nacos
nacos:
server-addr: localhost:8848
group: SEATA_GROUP
registry:
type: nacos
nacos:
application: seata-server
server-addr: localhost:8848
group: SEATA_GROUP
store:
mode: db # 事务日志存储模式,支持db、file、redis等
db:
datasource: druid
db-type: mysql
url: jdbc:mysql://localhost:3306/seata?useUnicode=true
user: root
password: root
2. 生产环境高可用部署 (docker-compose.yml)
通过Nginx负载均衡部署多个Seata Server实例,实现高可用。
version: '3.8'
services:
seata-server1:
image: seataio/seata-server:1.5.0
container_name: seata-server1
environment:
- SEATA_IP=seata-server1
- STORE_MODE=db
- DB_HOST=mysql
seata-server2:
image: seataio/seata-server:1.5.0
container_name: seata-server2
environment:
- SEATA_IP=seata-server2
- STORE_MODE=db
- DB_HOST=mysql
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf # Nginx负载均衡配置
六、生产环境最佳实践与调优
1. 性能优化配置参数
seata:
client:
rm:
report-success-enable: false # 分支事务一阶段成功是否立即上报,关闭以减少网络开销
async-commit-buffer-limit: 10000 # 异步提交缓冲区大小
tm:
commit-retry-count: 5 # 全局事务提交重试次数
undo:
data-validation: true # 开启Undo Log数据校验,防止脏数据
transport:
enable-client-batch-send-request: true # 启用客户端批量发送请求
compression: gzip # 启用网络传输压缩
2. 关键监控指标
建议监控以下核心指标以保障稳定性:
- 全局事务成功率:衡量系统事务健康度的核心指标。
- 分支事务平均耗时:定位性能瓶颈。
- 全局锁冲突次数:高并发下AT模式需重点关注,冲突过多可能影响吞吐量。
- Undo Log积压数量:反映二阶段清理是否正常。
七、面试要点深度解析
核心回答思路:
在微服务架构中,Seata通过TC、TM、RM三组件协作解决数据一致性问题。选择AT还是TCC模式是关键决策点:AT模式无侵入,通过SQL镜像实现自动回滚,适合大部分对最终一致性容忍度高的业务;TCC模式侵入性强,需要编码实现三阶段逻辑,但能保证强一致性,适用于交易、金融等核心场景。
高频深入问题:
- AT模式如何解决脏写?
通过全局锁机制。在一阶段,RM在操作数据前会向TC申请相关记录的全局锁。其他事务若要修改同一记录,必须等待该锁释放,从而避免了脏写。
- TCC的空回滚和悬挂如何产生与解决?
- 空回滚:Try未执行,Cancel先执行。解决方案:在Cancel逻辑中检查Try是否已执行(如查业务记录),若未执行则记录一条空回滚日志并直接返回成功。
- 悬挂:空回滚后,Try请求才到达。解决方案:在Try逻辑开始时,检查是否存在该业务键的空回滚记录,若存在则抛出异常或直接返回,避免业务悬挂。
- Seata性能瓶颈主要在哪?
- 全局锁竞争:在高并发更新同一热点数据时。
- 网络通信开销:TC与众多RM/TM之间的RPC通信。
- Undo Log的I/O操作:尤其是在AT模式下,每次数据更新都会产生并持久化镜像数据。