引言

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



如果服务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. 痞子衡嵌入式:ARM Cortex-M文件那些事(0)- 文件关联

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式开发里的文件关联. 本篇是文件系列第一篇,本系列文章会逐一介绍ARM Cortex-M开发过程中(以IAR集成开发环境为例,其他开发 ...

  2. python算法-选择排序

    核心算法:固定位置,选择元素,即:先从序列中,找到最小的元素,放在第一个位置,之后找到第二小的元素,放在第二个元素,以此类推,就可以完成整个排序工作了. 代码示例如下: x=[6,3,2,7,4,9, ...

  3. [日常] nginx记录post数据

    1.使用log_format指令来更改日志格式,该指令只能放在http{}段 log_format  日志名  '日志内容'; server { access_log /var/log/nginx/d ...

  4. CRM之分页

    分页简介 分页功能在网页中是非常常见的一个功能,其作用也就是将数据分割成多个页面来进行显示. 使用场景: 当取到的数据量达到一定的时候,就需要使用分页来进行数据分割. 当我们不使用分页功能的时候,会面 ...

  5. asp.net/wingtip/创建数据访问层

    一. 什么是数据访问层 在wingtip项目中,数据访问层是对以下三者的总称:1. product类等数据相关的实体类(class)2. 数据库(database),对实体类成员的存储3. 上述二者的 ...

  6. zabbix3.4 端口和进程监控配置

    虚拟机系统版本:centos7.5 zabbix server 版本:zabbix3.4 配置步骤:待定 近期即将更新!

  7. 使用 Nexus Repository Manager 搭建 npm 私服

    目录 环境 下载与安装 添加npm仓库 配置与验证npm仓库 发布自己的包 Nexus开启启动 脚注 环境 windows10(1803) Nexus Repository Manager OSS 3 ...

  8. JVM远程调试功能

    有时候想调试线上的程序 可以启用远程调试功能 在本地调试远程代码. 远程JVM启用调试模式 /usr/local/jdk/bin/java -server -Xms256m -Xmx256m -XX: ...

  9. Windows Server 2012 NIC Teaming 网卡绑定介绍及注意事项

    Windows Server 2012 NIC Teaming 网卡绑定介绍及注意事项 转载自:http://www.it165.net/os/html/201303/4799.html Window ...

  10. FIDDLER的使用方法及技巧总结

    转自: https://www.cnblogs.com/ink-marks/p/6363275.html 一.FIDDLER快速入门及使用场景 Fiddler的官方网站:http://www.fidd ...