TCC(Try-Confirm-Cancel)事务补偿机制

一、TCC基本概念

TCC(Try-Confirm-Cancel)是一种业务层面的分布式事务解决方案,通过将业务操作拆分为三个阶段来实现最终一致性。

与2PC/3PC等资源层协议不同,TCC需要业务代码显式实现各阶段逻辑


二、核心设计思想


TCC的核心思想是"预留资源+最终确认"


TCC分为两步骤,分别如下:

  • 第一步:Try(尝试),主要是对业务系统做检测及资源预留 (加锁,锁住资源)

  • 第二步:根据 Try 的结果,决定是执行confirm 还是 cancel


1、Confirm(确认):执行真正的业务(执行业务,释放锁)


2、Cancle(取消):是预留资源的取消(出问题,释放锁)


三、3个核心阶段


为了方便理解,下面以电商下单为例进行方案解析,这里把整个过程简单分为扣减库存,订单创建 2 个步骤,库存服务订单服务分别在不同的服务器节点上。


假设商品库存为 100,购买数量为 2,这里检查和更新库存的同时,冻结用户购买数量的库存,同时创建订单,订单状态为待确认。


1、Try阶段(尝试阶段)

  • 目的:预留业务资源,完成所有业务检查

  • 操作:

    • 冻结部分库存(电商)

    • 生成预订单(订单系统)

  • 特点:

    • 所有操作必须幂等

    • 不产生最终业务结果

    • 需要记录事务日志


2、Confirm阶段(确认阶段)

  • 目的:确认执行业务,使用Try阶段预留的资源

  • 操作:

    • 扣减冻结的库存

    • 确认订单生效

  • 特点:

    • 必须保证成功(不断重试直到成功)

    • 操作必须幂等

    • 不进行业务检查(已在Try阶段完成)


根据 Try 阶段服务是否全部正常执行,继续执行确认操作(Confirm)或 取消操作(Cancel)


Confirm 和 Cancel 操作满足幂等性,如果 Confirm 或 Cancel 操作执行失败,将会不断重试直到执行完成。


Confirm:当 Try 阶段服务全部正常执行, 执行确认业务逻辑操作,业务如下图:

这里使用的资源一定是 Try 阶段预留的业务资源。在 TCC 事务机制中认为,如果在 Try 阶段能正常的预留资源,那 Confirm 一定能完整正确的提交。


Confirm 阶段也可以看成是对 Try 阶段的一个补充, Try+Confirm 一起组成了一个完整的业务逻辑。


3、Cancel阶段(取消阶段)

  • 目的:取消Try阶段预留的资源

  • 操作:

    • 释放冻结的库存

    • 取消预订单

  • 特点:

    • 必须保证成功(不断重试直到成功)

    • 操作必须幂等

    • 需要处理Try阶段可能部分成功的情况


Cancel:当 Try 阶段存在服务执行失败, 进入 Cancel 阶段,业务如下图:

Cancel 取消执行,释放 Try 阶段预留的业务资源,上面的例子中,Cancel 操作会把冻结的库存释放,并更新订单状态为取消


四、最终一致性保证

  • TCC 事务机制以初步操作(Try)为中心的,确认操作(Confirm)和取消操作(Cancel)都是围绕初步操作(Try)而展开。因此,Try 阶段中的操作,其保障性是最好的,即使失败,仍然有取消操作(Cancel)可以将其执行结果撤销。

  • Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。也就是说只要Try成功,Confirm一定成功(TCC设计之初的定义) 。

  • Confirm与Cancel如果失败,由TCC框架进行重试补偿

  • 存在极低概率在CC环节彻底失败,则需要定时任务或人工介入


五、TCC工作流程

异常情况:

  • 任一Try失败:立即执行Cancel

  • Confirm 或 Cancel失败:不断重试


六、TCC的六大核心特性

1、业务侵入性:需要业务代码显式实现三个接口

2、最终一致性:通过重试机制保证最终一致

3、隔离性:通过资源预留防止脏读

4、幂等控制:每个阶段操作必须支持重复执行

5、空回滚:处理Try超时但实际成功的情况

6、防悬挂:防止Cancel比Try先到达


七、关键问题与解决方案


1、空回滚问题


场景:

  • Try未执行(网络超时)

  • 但协调者触发了Cancel


解决方案:

  • 在Try阶段记录事务日志

  • Cancel时检查是否有对应Try记录

  • 无记录时执行空回滚并记录


2、幂等控制


场景:

  • 网络重发导致重复调用


解决方案:

  • 每个事务使用唯一事务ID

  • 记录每个事务ID的执行状态

  • 重复请求直接返回之前的结果


3、防悬挂问题


场景:

  • Try因网络拥堵延迟到达

  • Cancel先执行完毕

  • 然后Try才到达


解决方案:

  • Cancel时记录已取消状态

  • Try执行前检查是否已被取消


八、典型应用场景


1、电商下单:

  • Try:冻结库存、预扣优惠券

  • Confirm:实际扣减

  • Cancel:释放资源


2、跨行转账:

  • Try:A行冻结金额,B行预增余额

  • Confirm:双方实际记账

  • Cancel:双方撤销操作


3、酒店预订:

  • Try:预留房间

  • Confirm:确认入住

  • Cancel:取消预订


实现模式


1、编码实现(业务耦合)


2、框架支持(推荐)

  • Seata(阿里开源)

  • ByteTCC

  • Himly

  • TCC-transaction

posted @ 2025-04-18 21:56  jock_javaEE  阅读(212)  评论(0)    收藏  举报