seata分布式事务TCC模式的原理和使用

今天分享seata分布式事务TCC模式的原理和使用:

一、seata分布式事务的原理

一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事
务组成的,分支事务要满足 两阶段提交 的模型要求,即需要每个分支事务都具备自己的:
1 、一阶段 prepare 行为
2 、二阶段 commit rollback 行为
 

TCC 模式,不依赖于底层数据资源的事务支持:

  • 一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
  • 二阶段 commit 行为:调用 自定义 的 commit 逻辑。
  • 二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。

所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

二、使用流程:

1、注解和配置

TCC 模式的 TM AT 模式的使用类似,只要在方法上面加上 @GlobalTransactional 注解就就可以了, file.conf 和 registry.conf 配置都跟 AT 模式一样。
 

2、TCC RM 的使用配置:

RM 的接口上面必须要有@LocalTCC 注解,且必须在接口上面,如图核心接口代码:

@LocalTCC//核心注解
@RequestMapping("/product/mall/service/manage/IKillService")
public interface IKillService {
    //核心方法配置
    @TwoPhaseBusinessAction(name = "updateByIdTcc", commitMethod = "updateIdTccCommit",
            rollbackMethod = "updateTccRollback")
    @RequestMapping(value = "/updateByIdTcc",
            method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    boolean updateByIdTcc(@RequestBody BusinessActionContext businessActionContext,
                          @BusinessActionContextParameter(paramName = "killGoodsPriceStr")
                          @RequestParam("killGoodsPriceStr") String killGoodsPriceStr);

    //提交方法
    @RequestMapping(value = "/updateIdTccCommit", method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    boolean updateIdTccCommit(@RequestBody BusinessActionContext businessActionContext);

    //回滚方法
    @RequestMapping(value = "/updateTccRollback", method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_VALUE)
    boolean updateTccRollback(@RequestBody BusinessActionContext businessActionContext);

}

三、TCC 使用过程中的几个典型问题及解决方案

1、空回滚

      首先是空回滚。什么是空回滚?空回滚就是对于一个分布式事务,在没有调用 TCC 资源 Try 方法的情况下,调用了二阶段的 Cancel 方法, Cancel 方法需要识别出这是一个空回滚,然 后直接返回成功。 什么样的情形会造成空回滚呢?如果调用 try 逻辑有问题,比如调用方机器宕机、网络异常, 都会造成 RPC 调用失败,即未执行 Try 方法。但是分布式事务已经开启了,需要推进到 终态,因此,TC 会回调参与者二阶段 Cancel 接口,从而形成空回滚。
 
解决方案:
 
        需要一张额外的事务控制表,其中有分布式事务 ID 和分支事务 ID ,第一阶段 Try 方法里 会插入一条记录,表示一阶段执行了。Cancel 接口里读取该记录,如果该记录存在,则正
常回滚;如果该记录不存在,则是空回滚。
 

2、悬挂

      悬挂就是对于一个分布式事务,其二阶段 Cancel 接口比 Try 接口先执行。因为允许空回滚 的原因,Cancel 接口认为 Try 接口没执行,空回滚直接返回成功,对于 Seata 框架来说,
认为分布式事务的二阶段接口已经执行成功,整个分布式事务就结束了。 但是这之后 Try 方 法才真正开始执行,预留业务资源,前面提到事务并发控制的业务加锁,对于一个 Try
法预留的业务资源,只有该分布式事务才能使用,然而 Seata 框架认为该分布式事务已经 结束,也就是说,当出现这种情况时,该分布式事务第一阶段预留的业务资源就再也没有人
能够处理了,对于这种情况,我们就称为悬挂,即业务资源预留后没法继续处理。
 
解决方案:
 
可以在二阶段执行时插入一条事务控制记录,状态为已回滚,这样当一阶段执行时,先读取 该记录,如果记录存在,就认为二阶段已经执行;否则二阶段没执行。
 

3、幂等

       幂等就是对于同一个分布式事务的同一个分支事务,重复去调用该分支事务的第二阶段接 口,因此,要求 TCC 的二阶段 Confirm Cancel 接口保证幂等,不会重复使用或者释
放资源。如果幂等控制没有做好,很有可能导致资损等严重问题。 什么样的情形会造成重复提交或回滚?从图中可以看到,提交或回滚是一次 TC 到参与者 的网络调用。因此,网络故障、参与者宕机等都有可能造成参与者 TCC 资源实际执行了二 阶段防范,但是 TC 没有收到返回结果的情况,这时, TC 就会重复调用,直至调用成功,
整个分布式事务结束。
 
解决方案:
 
        一个简单的思路就是记录每个分支事务的执行状态。在执行前状态,如果已执行,那就不再 执行;否则,正常执行。前面在讲空回滚的时候,已经有一张事务控制表了,事务控制表的 每条记录关联一个分支事务,那我们完全可以在这张事务控制表上加一个状态字段,用来记 录每个分支事务的执行状态。除此之外我们还应该要有业务幂等,比如查询支付状态,如果 是已经支付就不让再次支付了,直接结束二阶段。

 

到此seata分布式事务TCC模式原理和使用分享完成,下篇我们分析其源码执行流程。

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

寅灯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值