引言

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



如果服务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事务模型的更多相关文章

  1. 分布式事务之TCC事务模型

    一.引言 在上篇文章<老生常谈--利用消息队列处理分布式事务>一文中留了一个坑,今天来填坑.如下图所示 如果服务A和服务B之间是同步调用,比如服务C需要按流程调服务A和服务B,服务A和服务 ...

  2. 分布式事务之TCC服务设计和实现注意事项

    分布式事务之TCC服务设计和实现注意事项-云栖社区-阿里云 https://yq.aliyun.com/articles/609854 分布式事务之TCC事务丶一个站在Java后端设计之路的男青年个人 ...

  3. 转:分布式事务之TCC服务设计和实现注意事项

    由公司微服务培训引起的一丢丢对TCC的好奇 原文:https://yq.aliyun.com/articles/609854 一.TCC简介 TCC是一种比较成熟的分布式事务解决方案,可用于解决跨库操 ...

  4. Dubbo学习系列之十五(Seata分布式事务方案TCC模式)

    上篇的续集. 工具: Idea201902/JDK11/Gradle5.6.2/Mysql8.0.11/Lombok0.27/Postman7.5.0/SpringBoot2.1.9/Nacos1.1 ...

  5. 分布式事务Hmily TCC源码--学习整合

    一.什么是分布式事务 分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点上, 本质上来说,分布式事务是为了保证不同数据库的数据一致性 TCC事务主 ...

  6. 分布式事务解决方案(二)消息系统避免分布式事务 & MQ事务消息 & Sagas 事务模型

    参考文档: 如何用消息系统避免分布式事务:http://blog.jobbole.com/89140/ https://www.cnblogs.com/savorboard/p/distributed ...

  7. 分布式事务二TCC

    分布式事务解决方案之TCC 4.1.什么是TCC事务 TCC是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try.确认Confirm.撤销Cancel ...

  8. TCC事务原理

    本文主要介绍TCC的原理,以及从代码的角度上分析如何实现的:不涉及具体使用示例.本文分析的是github中开源项目tcc-transaction的代码,地址为:https://github.com/c ...

  9. QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付

    QNJR-GROUP/EasyTransaction: 依赖于Spring的一个柔性事务实现,包含 TCC事务,补偿事务,基于消息的最终一致性事务,基于消息的最大努力交付事务交付 大规模SOA系统的分 ...

随机推荐

  1. Docker 镜像之存储管理

    笔者在<Docker 镜像之进阶篇>中介绍了镜像分层.写时复制以及内容寻址存储(content-addressable storage)等技术特性,为了支持这些特性,docker 设计了一 ...

  2. Docker最全教程——从理论到实战(二)

    上篇内容链接: https://www.cnblogs.com/codelove/p/10030439.html Docker和ASP.NET Core Docker 正在逐渐成为容器行业的事实标准, ...

  3. 自动化运维工具fabric使用教程

    摘要:当需要同时管理许多服务器时,如果我们一台一台登陆上去操作会显得费时又费力.此时我们可以用fabric这个包提供的API来编写python脚本完成服务器集群的统一管理. 核心原理:fabric为主 ...

  4. 杭电ACM2006--求奇数的乘积

    求奇数的乘积 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  5. C# 如何创建Excel多级分组

    在Excel中如果能够将具有多级明细的数据进行分组显示,可以清晰地展示数据表格的整体结构,使整个文档具有一定层次感.根据需要设置显示或者隐藏分类数据下的详细信息,在便于数据查看.管理的同时也使文档更具 ...

  6. 30.C++复习篇

    本章学习内容: 1.const 2.指针const 3.inline内联函数 4.函数重载 5.extern “C” 6.new/delete声明与释放 7.namespace命名空间 8.C++中的 ...

  7. Maven(十二)Maven 依赖详解

    依赖的传递性 注意1:在Eclipise创建的Maven项目,若依赖eclipse空间中其他自己创建的 的项目时,此时并不会报错,但是当执行mvn compile命令时还是会显示缺失败.所以依赖的其他 ...

  8. 通过hash实现前端路由

    router.js //构造函数 function Router() { this.routes = {}; this.currentUrl = ''; } Router.prototype.rout ...

  9. openlayers3 实现点选的几种方式

    WebGIS开发中,点击查询是最常用的一种查询方式,在ArcGIS api 中,这种查询叫IdentifyTask,主要作用是前台提交参数,交ArcServer查询分析返回.本文从开源框架的角度,从前 ...

  10. AV-TEST杀毒软件能力测试(2018年1月-12月)杀毒软件排名

    2018年1月到12月,AV-TEST攻击了实验室中无数的Windows系统,在830多项单独测试中测试了7种杀毒软件和5种快捷工具. 1.测试概述 在长期测试中,实验室在各种实际场景中测试了杀毒软件 ...