🔄 Seata分布式事务模式详解

深入理解XA、AT、TCC、MQ四种事务模式的原理与应用

🔒

XA模式 (eXtended Architecture)

CP模式 - 强一致性

核心理念:基于X/Open XA规范的两阶段提交协议(2PC),确保分布式事务的ACID特性。在CAP理论中,XA模式选择了一致性(C)和分区容错性(P),牺牲了可用性(A)。

事务协调器

TC (Transaction Coordinator)

服务A

数据库A

服务B

数据库B

服务C

数据库C

🔄 两阶段提交流程:

阶段一(准备阶段 Prepare):TC向所有参与者发送prepare请求,参与者执行事务但不提交,返回准备结果
阶段二(提交阶段 Commit/Abort):如果所有参与者都准备成功,TC发送commit;否则发送rollback
锁定资源:从prepare到commit/rollback期间,所有相关资源被锁定,其他事务无法访问
同步等待:所有参与者必须等待协调器的最终决定,是阻塞式协议
强一致性:要么所有操作都成功,要么所有操作都失败,绝不允许数据不一致

优点

  • 强一致性保证:完全符合ACID特性,数据绝对可靠,适合金融等严格场景
  • 事务语义清晰:符合传统数据库事务概念,开发人员易于理解和使用
  • 数据库原生支持:主流数据库都支持XA协议,无需额外的框架开发
  • 标准化协议:遵循X/Open国际标准,具有良好的跨平台兼容性

缺点

  • 性能开销巨大:长时间锁定资源导致并发能力严重下降,吞吐量低
  • 阻塞式协议:所有参与者必须等待协调器决定,响应时间不可控
  • 单点故障风险:协调器故障会导致所有参与者永久阻塞
  • 网络分区敏感:网络故障可能导致数据不一致或系统长期阻塞

XA模式示例代码

// 1. 配置XA数据源
@Configuration
public class XADataSourceConfig {
    
    @Bean
    @Primary
    public DataSource dataSource() {
        AtomikosDataSourceBean dataSource = new AtomikosDataSourceBean();
        dataSource.setUniqueResourceName("xa-datasource");
        dataSource.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
        dataSource.setXaProperties(xaProperties());
        return dataSource;
    }
}

// 2. 业务服务使用全局事务注解
@Service
public class TransferService {
    
    @Autowired
    private AccountService accountService;
    
    @GlobalTransactional(rollbackFor = Exception.class)
    public void transferMoney(String fromAccount, String toAccount, BigDecimal amount) {
        try {
            // 第一阶段:所有操作都会执行但不提交
            
            // 步骤1:扣减源账户余额
            accountService.debit(fromAccount, amount);
            
            // 步骤2:增加目标账户余额
            accountService.credit(toAccount, amount);
            
            // 步骤3:记录转账日志
            logService.recordTransfer(fromAccount, toAccount, amount);
            
            // 如果所有步骤都成功,Seata会协调所有参与者提交事务
            // 如果任何步骤失败,所有操作自动回滚
            
        } catch (Exception e) {
            // 异常时,@GlobalTransactional会触发全局回滚
            throw e;
        }
    }
}

AT模式 (Automatic Transaction)

AP模式 - 最终一致性

核心理念:基于undo_log的自动补偿机制,在保证性能的同时实现分布式事务。AT模式选择了可用性(A)和分区容错性(P),通过最终一致性来平衡。

TC协调器

管理全局事务

业务数据

正常业务表

+

undo_log

回滚日志表

+

全局锁

行级锁机制

🔄 AT模式执行流程:

第一阶段:业务SQL执行,同时记录before image(修改前数据)和after image(修改后数据)到undo_log
本地提交:业务数据和undo_log在同一本地事务中提交,释放本地锁
注册分支:向TC注册分支事务,申请全局锁
第二阶段(成功):异步删除undo_log记录,释放全局锁
第二阶段(失败):根据undo_log的before image进行补偿回滚

优点

  • 性能优秀:无长时间资源锁定,本地事务快速提交,并发能力强
  • 零业务侵入:只需添加注解,无需修改现有业务逻辑代码
  • 数据库支持广泛:支持MySQL、Oracle、PostgreSQL等主流数据库
  • 自动回滚机制:基于undo_log自动生成补偿SQL,无需手动编写

缺点

  • 存储开销增加:需要额外的undo_log表存储回滚信息
  • SQL支持限制:不支持跨库Join、存储过程等复杂SQL操作
  • 脏回滚风险:高并发场景下可能出现数据被意外覆盖的问题
  • 数据库依赖:要求数据库支持行级锁和MVCC机制

AT模式示例代码

// 1. 创建undo_log表(Seata自动使用)
CREATE TABLE undo_log (
    id bigint(20) NOT NULL AUTO_INCREMENT,
    branch_id bigint(20) NOT NULL COMMENT '分支事务ID',
    xid varchar(100) NOT NULL COMMENT '全局事务ID',
    context varchar(128) NOT NULL COMMENT '事务上下文',
    rollback_info longblob NOT NULL COMMENT '回滚信息',
    log_status int(11) NOT NULL COMMENT '日志状态',
    log_created datetime NOT NULL COMMENT '创建时间',
    log_modified datetime NOT NULL COMMENT '修改时间',
    PRIMARY KEY (id),
    UNIQUE KEY ux_undo_log (xid,branch_id)
);

// 2. 业务服务 - AT模式使用
@Service
public class OrderService {
    
    @GlobalTransactional(rollbackFor = Exception.class)
    public void createOrder(Order order) {
        // 步骤1:创建订单
        orderRepository.save(order);
        
        // 步骤2:扣减库存
        stockService.reduceStock(order.getProductId(), order.getQuantity());
        
        // 步骤3:扣减账户余额
        accountService.deductBalance(order.getUserId(), order.getAmount());
    }
}
🎯

TCC模式 (Try-Confirm-Cancel)

AP模式 - 最终一致性

核心理念:通过Try、Confirm、Cancel三个阶段实现分布式事务,业务逻辑需要主动实现补偿机制。TCC是一种应用层的两阶段提交,给予业务更大的控制权。

Try阶段

预留资源
检查约束

Confirm阶段

确认执行
提交资源

Cancel阶段

取消执行
释放资源

🔄 TCC三阶段详解:

Try阶段:预留业务资源,检查业务约束,为后续确认或取消做准备(类似于2PC的prepare)
Confirm阶段:使用Try阶段预留的资源,真正执行业务操作(类似于2PC的commit)
Cancel阶段:释放Try阶段预留的资源,撤销已经执行的操作(类似于2PC的rollback)
幂等性要求:Confirm和Cancel操作都必须支持幂等,因为可能会重复调用
资源预留:Try阶段不直接修改业务数据,而是预留资源或记录操作意图

优点

  • 存储系统无关:不依赖特定数据库特性,支持NoSQL、缓存等各种存储系统
  • 性能可控:可以精确控制资源锁定的时间和范围,优化并发性能
  • 业务语义清晰:三阶段模式语义明确,便于理解和定制化开发
  • 复杂场景支持:能够处理跨系统、跨服务的复杂分布式事务场景

缺点

  • 开发成本高:需要为每个事务操作实现三个方法,开发工作量大
  • 代码侵入性强:需要重新设计和改造现有的业务逻辑代码
  • 一致性保障复杂:需要开发者自行保证各阶段的数据一致性
  • 维护成本高:错误排查、性能调优和系统维护相对复杂

TCC模式示例代码

// 1. TCC接口定义
@LocalTCC
public interface AccountTccService {
    
    @TwoPhaseBusinessAction(
        name = "debit", 
        commitMethod = "confirm", 
        rollbackMethod = "cancel"
    )
    boolean debit(@BusinessActionContextParameter(paramName = "userId") String userId,
                  @BusinessActionContextParameter(paramName = "amount") BigDecimal amount);
    
    boolean confirm(BusinessActionContext context);
    boolean cancel(BusinessActionContext context);
}

// 2. TCC实现 - Try阶段冻结金额
@Override
public boolean debit(String userId, BigDecimal amount) {
    // Try阶段:预留资源(冻结金额)
    Account account = accountRepository.findByUserId(userId);
    if (account.getBalance().compareTo(amount) < 0) {
        throw new RuntimeException("账户余额不足");
    }
    
    // 冻结金额
    FrozenAmount frozenAmount = new FrozenAmount();
    frozenAmount.setUserId(userId);
    frozenAmount.setAmount(amount);
    frozenAmount.setStatus("FROZEN");
    frozenAmountRepository.save(frozenAmount);
    
    return true;
}
📨

MQ模式 (Message Queue)

AP模式 - 最终一致性

核心理念:基于消息队列的事务消息机制,通过异步消息确保分布式事务的最终一致性。这是性能最优的方案,但需要业务容忍一定的延迟。

服务A

发送事务消息

消息队列

RocketMQ/Kafka

服务B

消费消息

服务C

消费消息

🔄 MQ事务消息流程:

发送半消息:生产者发送半消息(Half Message)到MQ服务器,此时消费者无法看到
执行本地事务:生产者执行本地数据库事务操作
确认消息:根据本地事务结果,确认提交或回滚半消息
消费消息:消费者接收到消息后执行相应的业务逻辑
回查机制:MQ定期回查生产者本地事务状态,确保消息状态一致

优点

  • 性能卓越:完全异步处理,不阻塞主业务流程,吞吐量最高
  • 系统高度解耦:服务间通过消息松耦合,便于系统扩展和维护
  • 高可用保障:支持消息持久化、集群部署和故障转移
  • 水平扩展性强:易于进行负载均衡和分布式部署

缺点

  • 一致性保障复杂:需要处理消息丢失、重复投递等各种异常情况
  • 时序和延迟问题:消息处理存在延迟,需要考虑消息顺序性
  • 架构复杂度增加:引入消息中间件增加了系统的整体复杂性
  • 问题排查困难:异步处理模式导致错误定位和调试相对复杂

MQ模式示例代码

// 1. 发送事务消息
@Service
public class OrderService {
    
    @Autowired
    private TransactionMQProducer producer;
    
    public void createOrder(Order order) {
        Message message = new Message(
            "ORDER_TOPIC", 
            "CREATE_ORDER",
            order.getOrderId(),
            JSON.toJSONString(order).getBytes()
        );
        
        TransactionSendResult result = producer.sendMessageInTransaction(message, order);
    }
}

// 2. 事务监听器
@Component
public class OrderTransactionListener implements TransactionListener {
    
    @Override
    public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        try {
            Order order = (Order) arg;
            orderRepository.save(order);
            return LocalTransactionState.COMMIT_MESSAGE;
        } catch (Exception e) {
            return LocalTransactionState.ROLLBACK_MESSAGE;
        }
    }
    
    @Override
    public LocalTransactionState checkLocalTransaction(MessageExt msg) {
        String orderId = msg.getKeys();
        Order order = orderRepository.findByOrderId(orderId);
        return order != null ? LocalTransactionState.COMMIT_MESSAGE 
                             : LocalTransactionState.ROLLBACK_MESSAGE;
    }
}
📊

四种模式对比总结

对比维度 XA模式 AT模式 TCC模式 MQ模式
一致性 强一致性 最终一致性 最终一致性 最终一致性
性能 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
开发复杂度 简单 简单 复杂 中等
业务侵入性 中等
适用场景 金融核心系统 一般业务系统 复杂业务场景 高并发异步场景
技术门槛 中等
资源锁定时间 可控 无锁定
支持的存储 支持XA的数据库 关系型数据库 任意存储 任意存储

🎯 选择建议

强一致性要求

选择 XA模式
适用于金融核心系统、支付系统等对数据一致性要求极高的场景

零侵入 + 高性能

选择 AT模式
适用于大部分业务场景,是最推荐的默认选择

复杂业务逻辑

选择 TCC模式
适用于定制化要求高、跨系统复杂业务场景

异步 + 高并发

选择 MQ模式
适用于高并发、允许异步处理的业务场景

💡 实际选择原则

  • 1. 数据一致性要求:强一致性选XA,最终一致性选AT/TCC/MQ
  • 2. 性能要求:高性能选AT/MQ,中等性能选TCC,低性能可接受选XA
  • 3. 开发成本:低成本选AT,中等成本选MQ,高成本选TCC
  • 4. 技术栈限制:考虑现有技术栈对各模式的支持程度
  • 5. 业务特性:同步业务选XA/AT/TCC,异步业务选MQ