分布式事务实战:Seata AT模式与TCC方案的落地对比

分布式事务是微服务绕不开的问题。订单服务扣库存、支付服务扣余额、积分服务加积分,三个数据库各管一段,任何一步失败都会产生数据不一致。强一致方案(XA两阶段提交)在互联网高并发场景几乎无人使用——同步阻塞、性能崩塌。工程上主流的是最终一致性路线:Seata AT模式覆盖通用场景,TCC覆盖强业务语义场景,本地消息表兜底异步链路。

Seata AT模式原理:两阶段无侵入补偿

AT模式的核心是undo_log:一阶段执行业务SQL时Seata代理数据源,解析SQL生成前后镜像存入undo_log表,与业务SQL同库同事务提交,全局锁防脏写。二阶段提交删除undo_log,回滚则用镜像反向补偿。

@GlobalTransactional(rollbackFor = Exception.class)
public void createOrder(OrderDTO dto) {
    orderFeign.create(dto);                    // 订单库
    stockFeign.deduct(dto.getSkuId(), dto.getCount());   // 库存库
    accountFeign.debit(dto.getUserId(), dto.getAmount()); // 余额库
}

接入成本低是最大优势:业务代码只需注解,SQL自动补偿。代价是全局锁竞争——热点行(秒杀SKU)在AT模式下锁竞争激烈,吞吐量掉一个数量级。回滚还有个前提:事务内别把业务校验和不可补偿的外部调用(如第三方支付接口)混在一起。

TCC模式:Try-Confirm-Cancel的业务侵入方案

TCC把事务控制权交给业务,三个接口语义自定义。以扣款为例:Try冻结金额,Confirm实际扣减,Cancel解冻。

@TwoPhaseBusinessAction(name = "debit", commitMethod = "confirm", rollbackMethod = "cancel")
public boolean tryDebit(BusinessActionContext ctx, String userId, BigDecimal amount) {
    return accountDAO.freeze(userId, amount);  // 冻结余额
}

public boolean confirm(BusinessActionContext ctx) {
    return accountDAO.deductFrozen((String) ctx.getActionContext("userId"));
}

public boolean cancel(BusinessActionContext ctx) {
    return accountDAO.unfreeze((String) ctx.getActionContext("userId"));
}

TCC没有全局锁,性能上限远高于AT,但要求每个参与者设计三个接口,开发成本翻倍。三个坑必须防:空回滚(Cancel先于Try执行)、悬挂(Cancel执行后Try才到达)、幂等(Confirm/Cancel可能重试多次),Seata提供防悬挂表与幂等控件,接口内的业务校验仍要自己兜底。

本地消息表+MQ:异步场景的最终一致性

跨服务调用链路长、实时性要求不高的场景(积分、通知),本地消息表更稳妥:业务操作与消息记录同一本地事务写入,MQ投递由后台任务扫描补发。

@Transactional
public void paySuccess(PayEvent event) {
    payDAO.updateStatus(event.getOrderId(), PAID);
    // 与业务同库同事务,保证原子性
    messageDAO.insert(new LocalMessage(event.getOrderId(), "ADD_POINT", event.toJson()));
}
// 定时任务扫描status=INIT的消息投递MQ,成功后标记DONE

消费端用幂等表去重,配合RocketMQ事务消息可省掉扫描任务。该方案的代价是延迟(秒级)与业务表里多出一张消息表,换来的是彻底解耦与天然重试。

方案选型决策:并发、语义与成本三角

决策路径:低并发内部服务用Seata AT,开发效率优先;热点资金类操作(扣款、扣库存)用TCC,锁粒度控制在业务字段级;跨系统异步链路(三方回调、通知、积分)用本地消息表+MQ。混合使用很常见:核心链路TCC,旁路链路消息表。落地时给每个参与方加监控埋点(全局事务状态、undo_log堆积量、消息表积压数),分布式事务的故障排查远比单库事务难,可观测性要提前建。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fen-bu-shi-shi-wu-shi-zhan-seataat-mo-shi-yu-tcc-fang-an-de/

(0)
小编小编
上一篇 8小时前
下一篇 8小时前

相关推荐