深度解析 Seata TCC 底层原理:三阶段机制、组件交互与一致性保障

197 阅读6分钟

Seata TCC 模式是基于 “分阶段资源预留” 思想实现的分布式事务方案,其核心是通过将分布式事务拆分为 Try(资源检查与预留)、Confirm(确认执行)、Cancel(取消回滚) 三个阶段,由业务代码自主控制资源的锁定与释放,最终保证全局事务的一致性。

一、TCC 模式的核心思想

TCC 是 补偿事务 的一种实现方式,核心逻辑是:

  1. 先尝试预留资源(Try 阶段),确保业务操作具备执行条件;
  2. 若所有参与者都预留成功,则确认执行(Confirm 阶段),实际消耗资源;
  3. 若任何参与者预留失败,则取消所有操作(Cancel 阶段),释放已预留的资源。

通过这种“先预留、再确认/取消”的机制,避免了分布式事务中“资源竞争”和“数据不一致”的问题。

二、Seata TCC 的核心组件与交互

Seata 作为分布式事务协调框架,在 TCC 模式中承担 “全局事务协调” 角色,核心组件包括:

  • TM(Transaction Manager):事务发起者,负责发起全局事务、决定事务提交或回滚。
  • RM(Resource Manager):事务参与者,每个微服务节点都是一个 RM,负责实现 TCC 的三个阶段逻辑,并向 TC 汇报分支事务状态。
  • TC(Transaction Coordinator):全局事务协调器(Seata Server 核心功能),负责维护全局事务状态、管理分支事务注册与状态,协调各 RM 执行 Confirm 或 Cancel。

三、Seata TCC 底层执行流程(核心原理)

以“订单服务调用账户服务(扣减余额)和库存服务(扣减库存)”为例,完整流程如下:

1. 全局事务创建(TM 发起)

  • 订单服务(TM)通过 @GlobalTransactional 注解标记全局事务入口,调用 TC 创建全局事务。
  • TC 生成 全局事务 ID(XID),并将全局事务状态初始化为“开始”(Begin)。
  • XID 通过 线程上下文 传递到所有参与的微服务(账户服务、库存服务),确保所有分支事务关联到同一全局事务。

2. Try 阶段(资源检查与预留)

  • 订单服务调用账户服务的 tryDeductBalance 方法(TCC 接口的 Try 方法):
    • 账户服务(RM)检查用户余额是否充足,若充足则 冻结金额(预留资源,如 balance 不变,frozen_balance 增加)。
    • 账户服务向 TC 注册 分支事务(关联 XID),并汇报 Try 阶段状态为“成功”或“失败”。
  • 订单服务继续调用库存服务的 tryDeductStock 方法:
    • 库存服务(RM)检查库存是否充足,若充足则 冻结库存(预留资源,如 stock 不变,frozen_stock 增加)。
    • 库存服务向 TC 注册分支事务,并汇报 Try 阶段状态。

3. 全局事务决策(TM 通知 TC)

  • 若所有参与者的 Try 阶段都成功,订单服务(TM)通知 TC“提交全局事务”。
  • 若任何参与者的 Try 阶段失败(如余额不足),订单服务(TM)通知 TC“回滚全局事务”。

4. Confirm 阶段(确认执行,仅当 Try 全成功)

  • TC 向所有参与者(账户服务、库存服务)发送“Confirm 指令”。
  • 账户服务执行 confirmDeductBalance 方法:
    • 将 Try 阶段冻结的金额 实际扣减balance 减少,frozen_balance 清零)。
    • 向 TC 汇报 Confirm 结果。
  • 库存服务执行 confirmDeductStock 方法:
    • 将 Try 阶段冻结的库存 实际扣减stock 减少,frozen_stock 清零)。
    • 向 TC 汇报 Confirm 结果。
  • 若所有参与者 Confirm 成功,TC 将全局事务状态标记为“已提交”。

5. Cancel 阶段(取消回滚,仅当 Try 有失败)

  • TC 向所有参与者发送“Cancel 指令”。
  • 账户服务执行 cancelDeductBalance 方法:
    • 释放 Try 阶段冻结的金额(frozen_balance 清零)。
    • 向 TC 汇报 Cancel 结果。
  • 库存服务执行 cancelDeductStock 方法:
    • 释放 Try 阶段冻结的库存(frozen_stock 清零)。
    • 向 TC 汇报 Cancel 结果。
  • 若所有参与者 Cancel 成功,TC 将全局事务状态标记为“已回滚”。

四、Seata TCC 的关键技术细节

1. 事务状态管理(TC 核心职责)

TC 通过 全局事务表(global_table)分支事务表(branch_table) 存储事务状态(DB 模式),或通过 Redis 键值对存储(Redis 模式):

  • global_table:记录 XID、全局事务状态(开始/提交/回滚)、超时时间等。
  • branch_table:记录每个分支事务的 ID、关联 XID、资源 ID(如 TCC 接口名)、分支状态(Try/Confirm/Cancel 结果)。

2. 幂等性保障(核心设计要求)

  • 问题:TC 可能因网络抖动重试发送 Confirm/Cancel 指令,导致重复执行。
  • 解决:业务代码必须实现幂等性(如通过 XID 或业务 ID 记录执行状态,重复调用时直接返回成功)。
  • Seata 不直接提供幂等性实现,需业务层自主保证(如基于 Redis 或数据库记录执行标记)。

3. 空回滚与悬挂处理

  • 空回滚:当某参与者未执行 Try 阶段,却收到 TC 的 Cancel 指令(如网络延迟导致 Try 未执行,但全局事务已决定回滚)。
    • 解决:在 Cancel 方法中检查 Try 阶段是否执行(如通过 XID 标记),未执行则直接返回成功。
  • 悬挂:Try 阶段因超时未完成,但 TC 已触发 Cancel,后续 Try 又执行成功(导致资源被错误预留)。
    • 解决:在 Try 方法中检查全局事务状态,若已触发 Cancel,则直接返回失败。

4. 超时控制

  • 全局事务超时:TM 可通过 @GlobalTransactional(timeoutMills = 30000) 设置超时时间,超时后 TC 自动触发回滚。
  • 分支事务超时:Seata 不直接控制分支超时,需业务层自主实现(如 Try 阶段设置业务超时,超时则返回失败)。

五、Seata TCC 与其他模式的核心区别

特性Seata TCC 模式Seata AT 模式(自动事务)
业务侵入性高(需手动实现 Try/Confirm/Cancel)低(自动生成 undo 日志,无需改业务代码)
适用场景复杂业务(如支付、库存、跨银行转账)简单 CRUD 场景(如订单创建、商品修改)
资源控制方式业务代码自主预留/释放资源(显式控制)框架自动通过 undo 日志回滚(隐式控制)
性能较高(无全局锁,业务自主控制资源)中等(需全局锁保证隔离性)
一致性保障强一致性(严格分阶段执行)最终一致性(依赖 undo 日志回滚)

六、总结

Seata TCC 模式的底层原理可概括为:
通过 TC 协调全局事务,将分布式操作拆分为“资源预留(Try)、确认执行(Confirm)、取消回滚(Cancel)”三阶段,由业务代码自主控制资源的锁定与释放,结合幂等性设计和异常处理,最终保证全局事务的一致性

其核心优势是灵活性高(适合复杂业务)和性能较好(无全局锁),但需业务开发者深度参与事务逻辑设计,因此更适合支付、金融等对一致性要求极高且业务复杂的场景。