Seata TCC 模式是基于 “分阶段资源预留” 思想实现的分布式事务方案,其核心是通过将分布式事务拆分为 Try(资源检查与预留)、Confirm(确认执行)、Cancel(取消回滚) 三个阶段,由业务代码自主控制资源的锁定与释放,最终保证全局事务的一致性。
一、TCC 模式的核心思想
TCC 是 补偿事务 的一种实现方式,核心逻辑是:
- 先尝试预留资源(Try 阶段),确保业务操作具备执行条件;
- 若所有参与者都预留成功,则确认执行(Confirm 阶段),实际消耗资源;
- 若任何参与者预留失败,则取消所有操作(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 阶段状态为“成功”或“失败”。
- 账户服务(RM)检查用户余额是否充足,若充足则 冻结金额(预留资源,如
- 订单服务继续调用库存服务的
tryDeductStock方法:- 库存服务(RM)检查库存是否充足,若充足则 冻结库存(预留资源,如
stock不变,frozen_stock增加)。 - 库存服务向 TC 注册分支事务,并汇报 Try 阶段状态。
- 库存服务(RM)检查库存是否充足,若充足则 冻结库存(预留资源,如
3. 全局事务决策(TM 通知 TC)
- 若所有参与者的 Try 阶段都成功,订单服务(TM)通知 TC“提交全局事务”。
- 若任何参与者的 Try 阶段失败(如余额不足),订单服务(TM)通知 TC“回滚全局事务”。
4. Confirm 阶段(确认执行,仅当 Try 全成功)
- TC 向所有参与者(账户服务、库存服务)发送“Confirm 指令”。
- 账户服务执行
confirmDeductBalance方法:- 将 Try 阶段冻结的金额 实际扣减(
balance减少,frozen_balance清零)。 - 向 TC 汇报 Confirm 结果。
- 将 Try 阶段冻结的金额 实际扣减(
- 库存服务执行
confirmDeductStock方法:- 将 Try 阶段冻结的库存 实际扣减(
stock减少,frozen_stock清零)。 - 向 TC 汇报 Confirm 结果。
- 将 Try 阶段冻结的库存 实际扣减(
- 若所有参与者 Confirm 成功,TC 将全局事务状态标记为“已提交”。
5. Cancel 阶段(取消回滚,仅当 Try 有失败)
- TC 向所有参与者发送“Cancel 指令”。
- 账户服务执行
cancelDeductBalance方法:- 释放 Try 阶段冻结的金额(
frozen_balance清零)。 - 向 TC 汇报 Cancel 结果。
- 释放 Try 阶段冻结的金额(
- 库存服务执行
cancelDeductStock方法:- 释放 Try 阶段冻结的库存(
frozen_stock清零)。 - 向 TC 汇报 Cancel 结果。
- 释放 Try 阶段冻结的库存(
- 若所有参与者 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)”三阶段,由业务代码自主控制资源的锁定与释放,结合幂等性设计和异常处理,最终保证全局事务的一致性。
其核心优势是灵活性高(适合复杂业务)和性能较好(无全局锁),但需业务开发者深度参与事务逻辑设计,因此更适合支付、金融等对一致性要求极高且业务复杂的场景。