一.引言

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

如果服务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和服务B要 ...

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

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

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

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

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

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

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

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

  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. 菜鸡的Java笔记 国际化程序实现原理

    国际化程序实现原理 Lnternationalization        1. Locale 类的使用        2.国家化程序的实现,资源读取                所谓的国际化的程序 ...

  2. 学习 DDD 之消化知识!

    接触到DDD到现在已经有8个月份了,目前所维护的项目也是基于DDD的思想开发的,从一开始的无从下手,到现在游刃有余,学到不少东西,但是都是一些关键字和零散的知识,同时我也感受到了是因为我对项目越来越熟 ...

  3. 记一次 android 线上 oom 问题

    背景 公司的主打产品是一款跨平台的 App,我的部门负责为它提供底层的 sdk 用于数据传输,我负责的是 Adnroid 端的 sdk 开发. sdk 并不直接加载在 App 主进程,而是隔离在一个单 ...

  4. [TopCoder2014Final]FrozenStandings 解法探究

    https://vjudge.net/problem/TopCoder-13460 简要题意:给出 \(n\) 段从 \(1\) 到 \(n\) 编号的等长区间,保证区间的端点互不相同.区间可以选取其 ...

  5. [省选联考 2021 A/B 卷] 宝石

    大概是一眼看出来是这个给定序列在树上序列上按顺序跑最大匹配. 然后考虑维护向上和向下的链的值. 大概的做法是用倍增维护,考虑\(f_{u,i}\)是\(c_u\)在序列里的位置向后匹配\(2^i\)位 ...

  6. 洛谷 P3246 - [HNOI2016]序列(单调栈+前缀和)

    题面传送门 这道题为什么我就没想出来呢/kk 对于每组询问 \([l,r]\),我们首先求出区间 \([l,r]\) 中最小值的位置 \(x\),这个可以用 ST 表实现 \(\mathcal O(n ...

  7. R数据科学-1

    R数据科学(R for Data Science) Part 1:探索 by: PJX for 查漏补缺 exercise: https://jrnold.github.io/r4ds-exercis ...

  8. shell 小数的比较大小问题

    经过实验,if 语句中的数值判断是不可以比较小数大小的:-gt -ne 2. 直接用awk awk -v  num1=6.6 -v num2=5.5  'BEGIN{print(num1>num ...

  9. mysql 中@ 和 @@的区别

    @x 是 用户自定义的变量 (User variables are written as @var_name)@@x 是 global或session变量 (@@global @@session )@ ...

  10. day07 ORM中常用字段和参数

    day07 ORM中常用字段和参数 今日内容 常用字段 关联字段 测试环境准备 查询关键字 查看ORM内部SQL语句 神奇的双下划线查询 多表查询前提准备 常用字段 字段类型 AutoField in ...