分布式事务之TCC事务模型
一.引言
在上篇文章《老生常谈——利用消息队列处理分布式事务》一文中留了一个坑,今天来填坑。如下图所示

如果服务A和服务B之间是同步调用,比如服务C需要按流程调服务A和服务B,服务A和服务B要么一起成功,要么一起失败。
针对这种情况,目前业内普遍推荐使用TCC事务来解决的!
二.正文
ok,老规矩,我们先套一个业务场景进去,如下图所示

那页面点了支付按钮,调用支付服务,那我们后台要实现下面三个步骤
[1] 订单服务-修改订单状态
[2] 账户服务-扣减金钱
[3] 库存服务-扣减库存
达到事务的效果,要么一起成功,要么一起失败!就要采取TCC分布式事务方案!
概念
TCC的全称是(Try-Confirm-Cancel)。如下图所示

ps:TCC又可以被称为两阶段补偿事务,第一阶段try只是预留资源,第二阶段要明确的告诉服务提供者,这个资源你到底要不要,对应第二阶段的confirm/cancel,用来清除第一阶段的影响,所以叫补偿型事务。
再打个比方,说TCC太高大上是吧,讲RM中的prepare、commit、rollback接口,总知道吧。可以类比的这么理解

那差别在哪呢?
rollback、commit、prepare,站在开发者层面是感知不到的,数据库帮你做了资源的操作!
而try、confirm、cancel,站在开发者层面是能感知到的,这三个方法的业务逻辑,即对资源的操作,开发者是要自己去实现的!
好,下面套入我们的场景,怎么做呢。比如,你的订单服务中本来只有一个接口
//修改代码状态
orderClient.updateStatus();
都要拆为三个接口,即
orderClient.tryUpateStatus();
orderClient.confirmUpateStatus();
orderClient.cancelUpateStatus();
注意了:面试官如果问你,TCC有什么缺点?这就是很严重的缺点,对代码入侵性大!每套业务逻辑、都要按try(请求资源)、confirm(操作资源)、cancel(取消资源),拆分为三个接口!
具体每个阶段,每个服务业务逻辑是什么样的呢?
假设,库存数量本来是50,那么可销售库存也是50。账户余额为50,可用余额也为50。用户下单,买了1个单价为1元的商品。流程如下:
Try阶段
订单服务:修改订单的状态为支付中
账户服务:账户余额不变,可用余额减1,然后将1这个数字冻结在一个单独的字段里
库存服务:库存数量不变,可销售库存减1,然后将1这个数字冻结在一个单独的字段里
confirm阶段
订单服务:修改订单的状态为支付完成
账户服务:账户余额变为(当前值减冻结字段的值),可用余额不变(Try阶段减过了),冻结字段清0。
库存服务:库存变为(当前值减冻结字段的值),可销售库存不变(Try阶段减过了),冻结字段清0。
cancel阶段
订单服务:修改订单的状态为未支付
账户服务:账户余额不变,可用余额变为(当前值加冻结字段的值),冻结字段清0。
库存服务:库存不变,可销售库存变为(当前值加冻结字段的值),冻结字段清0。
伪代码
接下来从代码程序来说明,为了便于演示,将入参略去。
本来,你支付服务的代码是长下面这样的

那么,用上TCC模型后,代码变成下面这样

注意了,这种写法其实严格上来说,不是不行。看你业务场景,因为存在一些瑕疵,看你自己有没办法接受
(1)cancel或者confirm出现异常了,你怎么处理?
例如在cancel阶段执行如下三行代码
orderClient.cancelUpdateStatus();
accountClient.cancelDecrease();
repositoryClient.cancelDecrease();
你第二行出现异常了,第三行没跑就退出了,怎么办?你要对此进行业务补偿!
(2)大量逻辑重复
你看啊,我们的执行架构其实是这样的
try{
xxclient.try();
}catch(Throwable t){
xxclient.cancel();
throw t;
}
xxclient.confirm();
有没办法让这个架子交给框架去执行,我们告诉框架,你在每个阶段要执行哪些方法就好!
因此,需要引入TCC分布式事务框架,事务的Try、Confirm、Cancel三个状态交给框架来感知!你只要告诉框架,Try要执行啥,Confirm要执行啥,Cancel要执行啥!如果Cancel过程出现异常了,框架有内部的补偿措施给你恢复数据!
以分布式tcc框架hmily为例,如果出现cancel异常或者confirm异常的情况,在try阶段会保存好日志,Hmily有内置的调度线程池来进行恢复,不用担心。
那hmily,怎么感知状态的呢?也很简单,就是切面编程,核心逻辑如下几行

我们在使用过程中,只要通过@Tcc注解告诉框架confirm方法执行啥,cancel方法执行啥即可!其他的交给框架帮你处理!
好了,不多说了,再说下去就是hmily源码解析了,大家有空自己去了解!
三.挖坑
注意看,《老生常谈——利用消息队列处理分布式事务》和本文所涉及到的微服务都是同一平台的。
那如果碰到,不同平台之间调用,你要怎么保证事务?比如,我的服务要调银行接口,你觉得可能让银行接你的tcc框架么?或者让银行接你的消息对列?你们觉得现实么?当然,有的人会说:"一个http直接调了。"嗯,少年有想法!
ok,那么业内针对这种涉及到第三方接口的服务调用,如何保证一致性?大家好好思考。
分布式事务之TCC事务模型的更多相关文章
- 【原创】分布式事务之TCC事务模型
引言 在上篇文章<老生常谈--利用消息队列处理分布式事务>一文中留了一个坑,今天来填坑.如下图所示 如果服务A和服务B之间是同步调用,比如服务C需要按流程调服务A和服务B,服务A和服务B要 ...
- 分布式事务之TCC服务设计和实现注意事项
分布式事务之TCC服务设计和实现注意事项-云栖社区-阿里云 https://yq.aliyun.com/articles/609854 分布式事务之TCC事务丶一个站在Java后端设计之路的男青年个人 ...
- 转:分布式事务之TCC服务设计和实现注意事项
由公司微服务培训引起的一丢丢对TCC的好奇 原文:https://yq.aliyun.com/articles/609854 一.TCC简介 TCC是一种比较成熟的分布式事务解决方案,可用于解决跨库操 ...
- 分布式事务Hmily TCC源码--学习整合
一.什么是分布式事务 分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点上, 本质上来说,分布式事务是为了保证不同数据库的数据一致性 TCC事务主 ...
- Dubbo学习系列之十五(Seata分布式事务方案TCC模式)
上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...
- 分布式事务解决方案(二)消息系统避免分布式事务 & MQ事务消息 & Sagas 事务模型
参考文档: 如何用消息系统避免分布式事务:http://blog.jobbole.com/89140/ https://www.cnblogs.com/savorboard/p/distributed ...
- 分布式事务二TCC
分布式事务解决方案之TCC 4.1.什么是TCC事务 TCC是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try.确认Confirm.撤销Cancel ...
- TCC事务原理
本文主要介绍TCC的原理,以及从代码的角度上分析如何实现的:不涉及具体使用示例.本文分析的是github中开源项目tcc-transaction的代码,地址为:https://github.com/c ...
- QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付
QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付 大规模SOA系统的分 ...
随机推荐
- python实现其它形态学操作
目录: (一) 顶帽(原图像与开操作图像的差值)(二) 黑帽(原图像与闭操作图像的差值)(三) 形态学梯度 (1)基本梯度(膨胀后的图像与腐蚀后的图像差值) (2)内部梯度(原图像减去腐蚀后的图像 ...
- [源码解析] PyTorch 分布式(10)------DistributedDataParallel 之 Reducer静态架构
[源码解析] PyTorch 分布式(10)------DistributedDataParallel之Reducer静态架构 目录 [源码解析] PyTorch 分布式(10)------Distr ...
- 描述高频题之队列&栈
栈和队列 全文概览 基础知识 栈 栈是一种先进后出的数据结构.这里有一个非常典型的例子,就是堆叠盘子.我们在放盘子的时候,只能从下往上一个一个的放:在取的时候,只能从上往下一个一个取,不能从中间随意取 ...
- Vue自定义组件实现v-model指令
Tips: 本文所描述的Vue均默认是Vue2版本 在我们初次接触Vue的时候,一定会了解到一个语法糖,那就是v-model指令,它带给我们的第一印象就是它可以实现双向绑定 那么,什么是双向绑定?通俗 ...
- 如何利用efetch从NCBI中批量下载数据?
目录 找序列 下序列 假设我要从NCBI中下载全部水稻的mRNA序列,如何实施? 找序列 第一步,肯定是找到相关序列. 我从ncbi taxonomy进入,搜索oryza.因为要搜索mRNA核酸序列, ...
- PHP 获取两个日期相差多少年,多少月,多少天,多少小时,并填充数组
PHP 获取两个日期相差多少年,多少月,多少天,多少小时,并填充数组 <?php /** * 获取两个日期相差多少年,多少月,多少天,多少小时,并填充数组 * @param [type] $st ...
- ggplot 局部放大
需要安装包:ggforce,下面以R自带数据做局部放大演示. require(ggplot2) require(ggforce) require(reshape2) data(CO2) co2< ...
- Linux服务器I/O性能分析-1
一.IOSTAT误区 1.1 误区-svctm Linux上的svctm是重要的I/O指标(I/O平均服务时间-单位毫秒),这个值直接反映了硬件的性能(I/O请求从SCSI层发出--->I/O完 ...
- Excel-统一小括号格式(中文小括号,英文小括号)
1.统一小括号格式(中文小括号,英文小括号) 公式=ASC("(") #"(" 解释函数: ASC(A1)#对于双字节字符集(DBCS)语言,将全角英文字符(即 ...
- exit(0) exit(1) return() 3个的区别
exit(0):正常运行程序并退出程序: exit(1):非正常运行导致退出程序: return():返回函数,若在主函数中,则会退出函数并返回一值. 详细说: 1. return返回函数值,是关键字 ...