分布式基础(十三)——分布式理论之分布式事务:TCC

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

 

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

 

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

 

一、简介

2007年,Pat Helland发表了一篇名为《Life beyond Distributed Transactions: an Apostate’s Opinion》的论文,提出了 TCC(Try-Confirm-Cancel) 的概念。

两阶段提交(2PC)三阶段提交(3PC)并不适用于并发量大的业务场景。TCC事务机制相比于2PC、3PC,不会锁定整个资源,而是通过引入 补偿机制 ,将资源转换为业务逻辑形式,锁的粒度变小。

TCC的核心思想是: 针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作 ,分为三个阶段:

  • Try: 这个阶段对各个服务的资源做检测以及对资源进行锁定或者预留;
  • Confirm : 执行真正的业务操作,不作任何业务检查,只使用Try阶段预留的业务资源,Confirm操作要求具备幂等设计,Confirm失败后需要进行重试;
  • Cancel: 如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,即执行回滚操作,释放Try阶段预留的业务资源 ,Cancel操作要求具备幂等设计,Cancel失败后需要进行重试。

举个例子,电商系统中有两个服务:订单服务A、库存服务B:
对外提供服务时,必须接受一些不确定性,即对服务A/B的一次调用仅是一个临时性操作,服务消费方保留了后续的取消权。
如果消费方认为全局事务应该rollback,它会要求取消之前的临时性操作;如果消费方认为全局事务应该commit时,它会进行的一个确认操作。

二、TCC的执行

TCC将一次事务操作分为三个阶段:Try、Confirm、Cancel,我们通过一个订单/库存的示例来理解。假设我们的分布式系统一共包含4个服务:订单服务、库存服务、积分服务、仓储服务,每个服务有自己的数据库,如下图:

2.1 Try

Try阶段一般用于锁定某个资源,设置一个预备状态或冻结部分数据。对于示例中的每一个服务,Try阶段所做的工作如下:

  • 订单服务:先置一个中间状态“UPDATING”,而不是直接设置“支付成功”状态;
  • 库存服务:先用一个冻结库存字段保存冻结库存数,而不是直接扣掉库存;
  • 积分服务:预增加会员积分;
  • 仓储服务:创建销售出库单,但状态是UNKONWN。

2.2 Confirm

根据Try阶段的执行情况,Confirm分为两种情况:

  1. 理想情况下,所有Try全部执行成功,则执行各个服务的Confirm逻辑;
  2. 部分服务Try执行失败,则执行第三阶段——Cancel。

Confirm阶段一般需要各个服务自己实现Confirm逻辑:

  • 订单服务:confirm逻辑可以是将订单的中间状态变更为PAYED-支付成功;
  • 库存服务:将冻结库存数清零,同时扣减掉真正的库存;
  • 积分服务:将预增加积分清零,同时增加真实会员积分;
  • 仓储服务:修改销售出库单的状态为已创建-CREATED。

Confirm阶段的各个服务本身可能出现问题,这时候一般就需要TCC框架了(比如ByteTCC,tcc-transaction,himly),TCC事务框架一般会记录一些分布式事务的活动日志,保存事务运行的各个阶段和状态,从而保证整个分布式事务的最终一致性。

2.3 Cancel

如果Try阶段执行异常,就会执行Cancel阶段。比如:对于订单服务,可以实现的一种Cancel逻辑就是:将订单的状态设置为“CANCELED”;对于库存服务,Cancel逻辑就是:将冻结库存扣减掉,加回到可销售库存里去。

许多公司为了简化TCC的使用,通常会将一个服务的某个核心接口拆成两个,比如库存服务的扣减库存接口,拆成两个子接口:①扣减接口 ②回滚扣减库存接口,由TCC框架来保证当某个接口执行失败后去执行对应的rollback接口。

三、总结

从正常的流程上讲,TCC仍然是一个两阶段提交协议。但是,在执行出现问题的时候,有一定的自我修复能力,如果任何一个事务参与者出现了问题,协调者可以通过执行逆操作来取消之前的操作,达到最终的一致状态(比如冲正交易、查询交易)。

从TCC的执行流程也可以看出,服务提供方需要提供额外的 补偿逻辑 ,那么原来一个服务接口,引入TCC后可能要改造成3种逻辑:

  • Try:先是服务调用链路依次执行Try逻辑;
  • Confirm:如果都正常的话,TCC分布式事务框架推进执行Confirm逻辑,完成整个事务;
  • Cancel:如果某个服务的Try逻辑有问题,TCC分布式事务框架感知到之后就会推进执行各个服务的Cancel逻辑,撤销之前执行的各种操作。

注意:在设计TCC事务时,接口的Cancel和Confirm操作都必须满足幂等设计。

3.1 框架选型

TCC框架的可供选择余地比较少,目前相对比较成熟的是阿里开源的分布式事务框架seata(Seata并不完全是一个TCC事务框架),这个框架是经历过阿里生产环境的大量考验,同时也支持dubbo、spring cloud。

3.2 优点

跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些,当然性能也可以得到提升。

3.3 缺点

TCC模型对业务的侵入性太强,事务回滚实际上就是自己写业务代码来进行回滚和补偿,改造的难度大。一般来说支付、交易等核心业务场景,可能会用TCC来严格保证分布式事务的一致性,要么全部成功,要么全部自动回滚。这些业务场景都是整个公司的核心业务有,比如银行核心主机的账务系统,不容半点差池。

但是,在一般的业务场景下,尽量别没事就用TCC作为分布式事务的解决方案,因为自己手写回滚/补偿逻辑,会造成业务代码臃肿且很难维护。

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值