分布式事务模式:2PC、3PC、TCC、Saga 与 Seata 实践

聊到分布式事务,很多人的第一反应就是「难」。说实话,我早年做单体应用时,事务就是个 @Transactional 注解的事。直到第一次接手微服务项目,订单、库存、积分三个服务各自独立,我才真正体会到什么叫「一个扣款成功,一个回滚失败」的噩梦。

分布式事务的核心问题,说白了就是:如何让多个独立数据库的操作,看起来像一次原子操作。今天我把几种主流模式串起来讲,最后再聊聊 Seata 这个国产框架怎么帮我们省事。

一、2PC:两阶段提交

2PC 是最经典的方案,分两个阶段走:

  • 准备阶段(投票):协调者问所有参与者「能提交吗?」
  • 提交阶段(执行):如果都同意,就正式提交;否则全部回滚。

我在项目中见过不少团队直接用 2PC,但踩坑的也不少。最大的问题是同步阻塞——协调者挂了,参与者就得一直等。另外,2PC 是强一致性,对性能影响很大。

适用场景:短事务、低并发、对一致性要求极高的内部系统。

二、3PC:三阶段提交

3PC 是 2PC 的改进版,多了一个 CanCommit 阶段。说白了就是先问一遍「能不能干」,再走 2PC 的流程。好处是减少了阻塞时间,但坏处是引入了更多网络开销。

我个人习惯把 3PC 看作「用网络换时间」——适合网络稳定的内网环境。但说实话,实际项目中用 3PC 的并不多,因为复杂度上去了,收益有限。

三、TCC:补偿型事务

TCC 是 Try-Confirm-Cancel 的缩写。我特别喜欢这个模式,因为它不依赖数据库锁,性能好很多。

  • Try:预留资源(比如冻结库存)
  • Confirm:确认执行(扣减库存)
  • Cancel:回滚释放(解冻库存)

我曾经在一个电商项目中用 TCC 处理库存扣减。注意,TCC 需要业务方自己实现 Cancel 逻辑,不能偷懒。比如你 Try 阶段冻结了 10 件商品,Cancel 时就得解冻 10 件,不能多也不能少。

避坑指南:我曾经因为 Cancel 逻辑没写幂等,导致重复解冻库存,最后对不上账。TCC 的 Cancel 和 Confirm 必须幂等。

四、Saga:长事务模式

Saga 把一个大事务拆成多个小事务,每个小事务都有对应的补偿操作。如果某个小事务失败,就依次执行前面所有事务的补偿。

举个例子:下单 -> 扣库存 -> 扣积分。如果扣积分失败,就补偿:加回库存 -> 取消订单。

Saga 有两种实现方式:

  • 编排式(Choreography):每个服务自己发事件,别人监听。适合简单链路。
  • 协调式(Orchestration):一个协调器统一调度。适合复杂链路。

我个人更推荐协调式,因为编排式的事件流一旦复杂起来,调试起来真的很头疼。

五、Seata 框架实践

Seata 是阿里开源的分布式事务框架,支持 AT、TCC、Saga 和 XA 四种模式。我项目中用得最多的是 AT 模式——它自动帮你生成反向 SQL,几乎无侵入。

下面是一个简单的 Seata AT 配置示例:

// 1. 引入依赖(Spring Boot)
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <version>1.6.1</version>
</dependency>

// 2. 配置 application.yml
seata:
  enabled: true
  application-id: order-service
  tx-service-group: my_test_tx_group
  service:
    vgroup-mapping:
      my_test_tx_group: default
    grouplist:
      default: 127.0.0.1:8091

// 3. 在业务方法上加注解
@GlobalTransactional
public void createOrder(Order order) {
    orderDao.insert(order);          // 本地事务
    stockService.deduct(order);      // 远程调用
    pointService.add(order);         // 远程调用
}

你看,代码几乎没变,就加了一个 @GlobalTransactional。Seata 会自动拦截 SQL,生成 undo_log,在失败时回滚。

小技巧:Seata 的 AT 模式依赖数据库的 undo_log 表,记得建表。另外,建议把 Seata Server 单独部署,别和业务服务混在一起。

六、模式对比与选型

模式 一致性 性能 侵入性 典型场景
2PC 短事务、低并发
3PC 内网稳定环境
TCC 最终 高并发、资源预留
Saga 最终 长事务、异步链路
Seata AT 最终 快速落地、无侵入

嗯,选型其实没有银弹。我个人的经验是:能不用分布式事务就不用,实在躲不过,优先考虑 Seata AT 或 TCC。Saga 适合异步场景,2PC 尽量少碰。

七、核心知识体系图

下面这张图帮你理清几种模式的关系和选型思路:

分布式事务模式选型 分布式事务 强一致性 2PC 3PC 最终一致性 TCC Saga Seata AT 选型建议 高并发、短事务 → TCC 或 Seata AT 长事务、异步链路 → Saga 低并发、强一致 → 2PC(慎用)

八、总结

分布式事务没有完美的方案,只有适合的方案。我这些年做下来,最大的体会是:先想清楚业务能不能接受最终一致性。如果能,TCC 和 Saga 是首选;如果不能,再考虑 2PC 或 Seata AT。

另外,别忘了 Seata 这个好工具。它把很多底层细节封装好了,让我们能专注于业务。嗯,如果你刚开始接触分布式事务,我建议先从 Seata AT 入手,跑通一个 demo 再说。

一句话记住:2PC 是「全有或全无」,TCC 是「预留再确认」,Saga 是「拆开补偿」,Seata 是「自动帮你搞定」。
公众号:蓝海资料掘金营,微信deep3321