事务--03---TCC空回滚、悬挂、幂等解决方案

2023-12-14 23:39:18

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


Seata TCC 模式设计思路

TCC 基于分布式事务中的二阶段提交协议实现,它的全称为 Try-Confirm-Cancel,即资源预留(Try)、确认操作(Confirm)、取消操作(Cancel),他们的具体含义如下:

  1. Try:对业务资源的检查并预留
  2. Confirm:对业务处理进行提交,即 commit 操作,只要 Try 成功,那么该步骤一定成功;
  3. Cancel:对业务处理进行取消,即回滚操作,该步骤回对 Try 预留的资源进行释放。

image.png

TCC存在的问题

1、空回滚以及解决方案

空回滚指的是在一个分布式事务中,在没有调用参与方的 Try 方法的情况下,TM 驱动二阶段回滚调用了参与方的 Cancel 方法。

image.png

  1. 如上图所示,全局事务开启后,参与者 A 分支注册完成之后会执行参与者一阶段 RPC 方法,如果此时参与者 A 所在的机器发生宕机,网络异常,都会造成 RPC 调用失败,即参与者 A 一阶段方法未成功执行
  2. 但是此时全局事务已经开启,Seata 必须要推进到终态,在全局事务回滚时会调用参与者 A 的 Cancel 方法,从而造成空回滚。

要想防止空回滚,那么必须在 Cancel 方法中识别这是一个空回滚,Seata 是如何做的呢?

解决方案:
  1. Seata 的做法是新增一个 TCC 事务控制表,包含事务的 XID 和 BranchID 信息,
  2. 在 Try 方法执行时插入一条记录,表示一阶段执行了
  3. 执行 Cancel 方法时读取这条记录,如果记录不存在,说明 Try 方法没有执行。
    在这里插入图片描述

2、幂等问题以及解决方案

幂等问题指的是 TC 重复进行二阶段提交,因此 Confirm/Cancel 接口需要支持幂等处理,即不会产生资源重复提交或者重复释放。

image.png

如上图所示,参与者 A 执行完二阶段之后,由于网络抖动或者宕机问题,会造成 TC 收不到参与者 A 执行二阶段的返回结果,TC 会重复发起调用,直到二阶段执行结果成功。

Seata 是如何处理幂等问题的呢?

解决方案:

同样的也是在 TCC 事务控制表中增加一个记录状态的字段 status,该字段有 3 个值,分别为:

  1. tried:1
  2. committed:2
  3. rollbacked:3

二阶段 Confirm/Cancel 方法执行后,将状态改为 committed 或 rollbacked 状态。当重复调用二阶段 Confirm/Cancel 方法时,判断事务状态即可解决幂等问题。

在这里插入图片描述

3、悬挂问题以及解决方案

悬挂指的是二阶段 Cancel 方法比 一阶段 Try 方法优先执行,由于允许空回滚的原因,在执行完二阶段 Cancel 方法之后直接空回滚返回成功,此时全局事务已结束,但是由于 Try 方法随后执行,这就会造成一阶段 Try 方法预留的资源永远无法提交和释放了

image.png

如上图所示,在执行参与者 A 的一阶段 Try 方法时,出现网路拥堵,由于 Seata 全局事务有超时限制,执行 Try 方法超时后,TM 决议全局回滚,回滚完成后如果此时 RPC 请求才到达参与者 A,执行 Try 方法进行资源预留,从而造成悬挂。

Seata 是怎么处理悬挂的呢?

解决方案:

在 TCC 事务控制表记录状态的字段 status 中增加一个状态:

*suspended:4

当执行二阶段 Cancel 方法时,如果发现 TCC 事务控制表没有相关记录,说明二阶段 Cancel 方法优先一阶段 Try 方法执行,因此插入一条 status=4 状态的记录,当一阶段 Try 方法后面执行时,判断 status=4 ,则说明有二阶段 Cancel 已执行,并返回 false 以阻止一阶段 Try 方法执行成功。

在这里插入图片描述

文章来源:https://blog.csdn.net/weixin_48052161/article/details/135005271
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。