分布式事务Seata TCC模式篇
介绍
官网: https://seata.apache.org/zh-cn/docs/user/mode/tcc
回顾Seata AT 模式基于 支持本地 ACID 事务 的 关系型数据库,如下:
- 一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
- 二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
- 二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。(如果已经被其他事务修改,可能回滚失败,需考虑策略)
当前Seata TCC (Try-Confirm-Cancel)模式则不不依赖于底层数据资源的事务支持,如下:
- 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑,又称为Try阶段,进行资源检查与预留
- 二阶段 commit 行为:调用 自定义 的 commit 逻辑,又称为Confirm阶段,在全局事务提交时执行,仅使用Try预留的资源,要求操作必须成功且幂等。
- 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑,又称为Cancel阶段,在全局事务回滚时触发,释放Try阶段预留的资源,同样需要保证幂等性。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。是高性能分布式事务解决方案,适用于核心系统等对性能有很高要求的场景。
TCC 完全不依赖底层数据库,能够实现跨数据库、跨应用资源管理。需要业务系统自行实现 Try,Confirm,Cancel 三个操作,对业务系统有着非常大的入侵性,设计相对复杂。
TCC模式示例
电商扣库存例子
1、Try阶段(资源预留)
用户下单触发库存服务冻结库存,优惠卷服务锁定优惠卷,积分服务预扣积分
以库存表设计为例,需要设计资源预留字段(冻结库存),在Cancel时精准恢复库存,避免数据错乱
CREATE TABLE product_stock (product_id BIGINT PRIMARY KEY,available_stock INT, -- 可售库存(实际可卖数量)frozen_stock INT -- 冻结库存(TCC预留数量)...
);
进行冻结库存 update product_stock set frozen_stock = frozen_stock + 1, available_stock = available_stock -1 where product_id=123
,其他的(锁定优惠券、预扣积分)所有都返回成功,才能进入下一阶段。
2、Confirm阶段(正式提交)
正式提交时进行扣减冻结库存,核销优惠券,正式扣除积分
以库存表为例,此时需要减去冻结库存
/* 仅减少冻结库存(不碰可用库存) */
UPDATE product_stock
SET frozen_stock = frozen_stock - 1 -- 释放冻结额度
WHERE product_id = 123;
3、Cancel阶段(回滚释放)
出现Cancel主要原因是因业务异常或系统故障导致事务无法完成,如try阶段库存服务响应成功,优惠卷服务未响应,则触发回滚
update product_stock set frozen_stock = frozen_stock - 1 , available_stock = available_stock + 1 where product_id=123
原理分析
Seata角色说明
- TC (Transaction Coordinator):事务协调器,全局事务调度中心(Seata-Server)。
- TM (Transaction Manager):事务管理器,用于触发开启/提交/回滚全局事务。而事务管理器分 2 阶段协调所有资源管理器,在第一阶段询问所有资源管理器**“准备”(Try)是否成功**,如果所有资源均“准备”成功则在第二阶段执行所有资源的**“提交”(Confirm)操作**,否则在第二阶段执行所有资源的**“回滚”(Cancel)操作**,保证所有资源的最终状态是一致的,要么全部提交要么全部回滚。
- RM (Resource Manager):资源管理器,分支事务注册与三阶段方法的真正执行。提供“准备”、“提交”和“回滚” 3 个操作的资源对应 Try、Confirm、Cancel 3 个方法均由业务编码实现 。
0、核心流程设计
- 事务启动:TM通过
GlobalTransactionalInterceptor
拦截业务方法,向TC注册全局事务生成XID。 - 分支注册:TCC服务(如扣库存)被调用时,
TccActionInterceptor
拦截Try方法,向TC注册分支事务并记录资源预留信息。
RM启动时,通过TCCResourceManager
向TC注册TCC资源(含Commit/Rollback方法信息),建立ResourceID到RPC上下文的映射
- 二阶段决策:
- 提交:TM通知TC → TC遍历分支事务 → 异步调用各RM的Confirm方法。
- 回滚:流程类似,调用Cancel方法,失败重试直至成功。
常见问题解决
0、TCC vs AT模式的核心差异
TCC需业务编码实现三阶段,无全局锁,适合高性能与非事务型数据库;AT依赖数据库快照和全局锁,对代码无侵入
1、空回滚(Cancel未执行Try),如何识别空回滚
Try因网络超时未执行,但全局事务因超时触发回滚Cancel。
可以通过查询事务记录表,若无对应XID的Try记录,则判定为空回滚,直接返回成功
- 事务记录表记录Try状态(如
tcc_status(xid, branch_id, status)
) - Cancel执行时检查记录:无记录则空回滚(直接返回成功)
2、**悬挂(Cancel先于Try执行)**如何解决
Try网络延迟,Cancel执行后Try才到达,导致资源永久锁定。
在Cancel执行时插入回滚记录(状态CANCELLED
),Try执行前检查此记录。若存在则放弃Try,避免资源锁定
- Try执行前检查事务记录表,若存在
CANCELLED
状态则拒绝执行。 - 分布式锁确保Try/Cancel互斥(如Redis锁)
3、幂等控制,如何保证
网络重传或补偿机制导致Confirm/Cancel重复调用。
通过事务记录表状态机实现。二阶段执行后更新状态,重复调用时根据状态直接返回
- 事务记录表增加状态字段(如
init
/committed
/cancelled
),二阶段执行后更新状态,重复调用时直接返回