分布式事务TCC 你真的理解了吗

TCC是一种柔性事务处理方式,包括Try、Confirm、Cancel三个阶段,用于确保业务的一致性。Try阶段检查和预留资源,Confirm执行实际操作,Cancel则取消预留资源。TM事务管理器负责协调,幂等性设计防止重复操作。文章提到了空回滚、幂等性和悬挂问题的解决方案,并提及了ByteTCC、Seata和Hmily等开源框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TCC(补偿事务)

TCC 属于目前比较火的一种柔性事务解决方案。TCC 这个概念最早诞生于数据库专家帕特 · 赫兰德(Pat Helland)于 2007 发表的 《Life beyond Distributed Transactions: an Apostate’s Opinion》 这篇论文,感兴趣的小伙伴可以阅读一下这篇论文。

三个阶段

简单来说,TCC 是 Try、Confirm、Cancel 三个词的缩写,它分为三个阶段:

  • Try(尝试)阶段 : 尝试执行

完成业务检查,并预留好必需的业务资源

  • Confirm(确认)阶段 :确认执行

当所有事务参与者的 Try 阶段执行成功就会执行 Confirm ,Confirm 阶段会处理 Try 阶段预留的业务资源。否则,就会执行 Cancel 。

通常情况下,采用 TCC 则认为 Confirm 阶段是不会出错的。即:只要 Try 成功,Confirm 一定成功。若 Confirm 阶段真的出错了,需引入重试机制或人工处理。

  • Cancel(取消)阶段 :取消执行,释放 Try 阶段预留的业务资源

通常情况下,采用 TCC 则认为 Cancel 阶段也是一定成功的。若 Cancel 阶段真的出错了,需引入重试机制或人工处理。

TM 事务管理器
  • TM 事务管理器可以实现为独立的服务,也可以让全局事务发起方充当 TM 的角色,TM 独立出来是为了成为公共组件,是为了考虑系统结构和软件复用
  • TM 在发起全局事务时生成全局事务记录,全局事务 ID 贯穿整个分布式事务调用链条,用来记录事务上下文,追踪和记录状态,由于 Confirm 和 Cancel 失败需要重试,因此需要实现幂等性,幂等性是指同一个操作无论请求多少次,其结果都相同
示例介绍

我们拿转账场景来说:

  • Try(尝试)阶段 : 在转账场景下,Try 要做的事情是就是检查账户余额是否充足,预留的资源就是转账资金

  • Confirm(确认)阶段 : 如果 Try 阶段执行成功的话,Confirm 阶段就会执行真正的扣钱操作

  • Cancel(取消)阶段 :释放 Try 阶段预留的转账资金

一般情况下,当我们使用 TCC 模式的时候,需要自己实现 try, confirm, cancel 这三个方法,来达到最终一致性。也就是说,正常情况下会执行 try, confirm,如下图所示。

img

出现异常的话会执行 try, cancel ,如下图所示。

img

因此,TCC 模式不需要依赖于底层数据资源的事务支持,但是需要我们手动实现更多的代码,属于 侵入业务代码 的一种分布式解决方案。

针对 TCC 的实现,业界也有一些不错的开源框架。不同的框架对于 TCC 的实现可能略有不同,不过大致思想都一样。

  1. ByteTCC : ByteTCC 是基于 Try-Confirm-Cancel(TCC)机制的分布式事务管理器的实现。 相关阅读:关于如何实现一个 TCC 分布式事务框架的一点思考

  2. Seata :Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。

  3. Hmily : 金融级分布式事务解决方案。

空回滚、幂等、悬挂

空回滚:

  • 在没调用 Try 方法的情况下,调用了第二阶段的 Cancel 方法,Cancel 方法需要识别出这是一个空回滚,然后直接返回成功
  • 出现原因是当一个分支事务所在服务宕机或网络异常,分支事务调用记录为失败,这个时候其实是没有执行 Try 阶段,当故障恢复后,分布式事务进行回滚则会调用第二阶段的 Cacel 方法,从而形成空回滚
  • 解决思路是关键就是要识别出这个空回滚。思路很简单就是需要知道一阶段是否执行,如果执行了,那就是正常回滚。如果没有执行,那就是空回滚。前面已经说过 TM 在发起全局事务时生成全局事务记录,全局事务 ID 贯穿整个分布式事务调用链条。再额外增加一张分支事务记录表,其中有全局事务 ID 和分支事务 ID,第一阶段 Try 方法里会插入一条记录,表示一阶段执行了。Cancel 接口里读取该记录,如果该记录存在,则正常回滚;如果该记录不存在,则是空回滚

幂等:

  • 通过前面介绍已经了解到,为了保证 TCC 二阶段提交重试机制不会引发数据不一致,要求 TCC 的二阶段 Try、Confirm 和 Cancel 接口保证幂等,这样不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致数据不一致等严重问题
  • 解决思路在上述“分支事务记录”中增加执行状态,每次执行前都查询该状态

悬挂:

  • 悬挂就是对于一个分布式事务,其二阶段 Cancel 接口比 Try 接口先执行
  • 出现原因是在 RPC 调用分支事务 try 时,先注册分支事务,再执行 RPC 调用,如果此时 RPC 调用的网络发生拥堵,通常 RPC 调用是有超时时间的,RPC 超时以后,TM 就会通知 RM 回滚该分布式事务,可能回滚完成后,RPC 请求才到达参与者真正执行,而一个 Try 方法预留的业务资源,只有该分布式事务才能使用,该分布式事务第一阶段预留的业务资源就再也没有人能够处理了,对于这种情况,我们就成为悬挂,即业务资源预留后没法继续处理
  • 解决思路时候如果二阶段执行完成,那一阶段就不能再继续执行。再执行一阶段事务时判断在该全局事务下,“分支事务记录”表中是否已经有二阶段事务记录,如果有则不执行 Try

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郎涯技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值