一、写在前面

之前网上看到很多写分布式事务的文章,不过大多都是将分布式事务各种技术方案简单介绍一下。很多朋友看了不少文章,还是不知道分布式事务到底怎么回事,在项目里到底如何使用。

所以咱们这篇文章,就用大白话+手工绘图,并结合一个电商系统的案例实践,来给大家讲清楚到底什么是TCC分布式事务。

首先说一下,这里可能会牵扯到一些Spring Cloud的原理,如果有不太清楚的同学,可以参考之前的文章:《拜托,面试请不要再问我Spring Cloud底层原理!》。

二、业务场景介绍

咱们先来看看业务场景,假设你现在有一个电商系统,里面有一个支付订单的场景。

那对一个订单支付之后,我们需要做下面的步骤:

  • 更改订单的状态为“已支付”

  • 扣减商品库存

  • 给会员增加积分

  • 创建销售出库单通知仓库发货

这是一系列比较真实的步骤,无论大家有没有做过电商系统,应该都能理解。

三、进一步思考

好,业务场景有了,现在我们要更进一步,实现一个TCC分布式事务的效果。

什么意思呢?也就是说,订单服务-修改订单状态,库存服务-扣减库存,积分服务-增加积分,仓储服务-创建销售出库单。

上述这几个步骤,要么一起成功,要么一起失败,必须是一个整体性的事务

举个例子,现在订单的状态都修改为“已支付”了,结果库存服务扣减库存失败。那个商品的库存原来是100件,现在卖掉了2件,本来应该是98件了。

结果呢?由于库存服务操作数据库异常,导致库存数量还是100。这不是在坑人么,当然不能允许这种情况发生了!

但是如果你不用TCC分布式事务方案的话,就用个Spring Cloud开发这么一个微服务系统,很有可能会干出这种事儿来。

我们来看看下面的这个图,直观的表达了上述的过程。

所以说,我们有必要使用TCC分布式事务机制来保证各个服务形成一个整体性的事务。

上面那几个步骤,要么全部成功,如果任何一个服务的操作失败了,就全部一起回滚,撤销已经完成的操作。

比如说库存服务要是扣减库存失败了,那么订单服务就得撤销那个修改订单状态的操作,然后得停止执行增加积分和通知出库两个操作。

说了那么多,老规矩,给大家上一张图,大伙儿顺着图来直观的感受一下。

四、落地实现TCC分布式事务

那么现在到底要如何来实现一个TCC分布式事务,使得各个服务,要么一起成功?要么一起失败呢?

大家稍安勿躁,我们这就来一步一步的分析一下。咱们就以一个Spring Cloud开发系统作为背景来解释。

1、TCC实现阶段一:Try

首先,订单服务那儿,他的代码大致来说应该是这样子的:

如果你之前看过Spring Cloud架构原理那篇文章,同时对Spring Cloud有一定的了解的话,应该是可以理解上面那段代码的。其实就是订单服务完成本地数据库操作之后,通过Spring Cloud的Feign来调用其他的各个服务罢了。

但是光是凭借这段代码,是不足以实现TCC分布式事务的啊?!兄弟们,别着急,我们对这个订单服务修改点儿代码好不好。

首先,上面那个订单服务先把自己的状态修改为:OrderStatus.UPDATING

这是啥意思呢?也就是说,在pay()那个方法里,你别直接把订单状态修改为已支付啊!你先把订单状态修改为UPDATING,也就是修改中的意思。

这个状态是个没有任何含义的这么一个状态,代表有人正在修改这个状态罢了。

然后呢,库存服务直接提供的那个reduceStock()接口里,也别直接扣减库存啊,你可以是冻结掉库存

举个例子,本来你的库存数量是100,你别直接100 - 2 = 98,扣减这个库存!

你可以把可销售的库存:100 - 2 = 98,设置为98没问题,然后在一个单独的冻结库存的字段里,设置一个2。也就是说,有2个库存是给冻结了。

积分服务的addCredit()接口也是同理,别直接给用户增加会员积分。你可以先在积分表里的一个预增加积分字段加入积分。

比如:用户积分原本是1190,现在要增加10个积分,别直接1190 + 10 = 1200个积分啊!

你可以保持积分为1190不变,在一个预增加字段里,比如说prepare_add_credit字段,设置一个10,表示有10个积分准备增加。

仓储服务的saleDelivery()接口也是同理啊,你可以先创建一个销售出库单,但是这个销售出库单的状态是“UNKNOWN”。

也就是说,刚刚创建这个销售出库单,此时还不确定他的状态是什么呢!

上面这套改造接口的过程,其实就是所谓的TCC分布式事务中的第一个T字母代表的阶段,也就是Try阶段

总结上述过程,如果你要实现一个TCC分布式事务,首先你的业务的主流程以及各个接口提供的业务含义,不是说直接完成那个业务操作,而是完成一个Try的操作。

这个操作,一般都是锁定某个资源,设置一个预备类的状态,冻结部分数据,等等,大概都是这类操作。

咱们来一起看看下面这张图,结合上面的文字,再来捋一捋这整个过程。

2、TCC实现阶段二:Confirm

然后就分成两种情况了,第一种情况是比较理想的,那就是各个服务执行自己的那个Try操作,都执行成功了,bingo!

这个时候,就需要依靠TCC分布式事务框架来推动后续的执行了。

这里简单提一句,如果你要玩儿TCC分布式事务,必须引入一款TCC分布式事务框架,比如国内开源的ByteTCC、himly、tcc-transaction。

否则的话,感知各个阶段的执行情况以及推进执行下一个阶段的这些事情,不太可能自己手写实现,太复杂了。

如果你在各个服务里引入了一个TCC分布式事务的框架,订单服务里内嵌的那个TCC分布式事务框架可以感知到,各个服务的Try操作都成功了。

此时,TCC分布式事务框架会控制进入TCC下一个阶段,第一个C阶段,也就是Confirm阶段

为了实现这个阶段,你需要在各个服务里再加入一些代码。比如说,订单服务里,你可以加入一个Confirm的逻辑,就是正式把订单的状态设置为“已支付”了,大概是类似下面这样子:

库存服务也是类似的,你可以有一个InventoryServiceConfirm类,里面提供一个reduceStock()接口的Confirm逻辑,这里就是将之前冻结库存字段的2个库存扣掉变为0。

这样的话,可销售库存之前就已经变为98了,现在冻结的2个库存也没了,那就正式完成了库存的扣减。

积分服务也是类似的,可以在积分服务里提供一个CreditServiceConfirm类,里面有一个addCredit()接口的Confirm逻辑,就是将预增加字段的10个积分扣掉,然后加入实际的会员积分字段中,从1190变为1120。

仓储服务也是类似,可以在仓储服务中提供一个WmsServiceConfirm类,提供一个saleDelivery()接口的Confirm逻辑,将销售出库单的状态正式修改为“已创建”,可以供仓储管理人员查看和使用,而不是停留在之前的中间状态“UNKNOWN”了。

好了,上面各种服务的Confirm的逻辑都实现好了,一旦订单服务里面的TCC分布式事务框架感知到各个服务的Try阶段都成功了以后,就会执行各个服务的Confirm逻辑。

订单服务内的TCC事务框架会负责跟其他各个服务内的TCC事务框架进行通信,依次调用各个服务的Confirm逻辑。然后,正式完成各个服务的所有业务逻辑的执行。

同样,给大家来一张图,顺着图一起来看看整个过程。

3、TCC实现阶段三:Cancel

好,这是比较正常的一种情况,那如果是异常的一种情况呢?举个例子:在Try阶段,比如积分服务吧,他执行出错了,此时会怎么样?

那订单服务内的TCC事务框架是可以感知到的,然后他会决定对整个TCC分布式事务进行回滚。也就是说,会执行各个服务的第二个C阶段,Cancel阶段

同样,为了实现这个Cancel阶段,各个服务还得加一些代码。

首先订单服务,他得提供一个OrderServiceCancel的类,在里面有一个pay()接口的Cancel逻辑,就是可以将订单的状态设置为“CANCELED”,也就是这个订单的状态是已取消。

库存服务也是同理,可以提供reduceStock()的Cancel逻辑,就是将冻结库存扣减掉2,加回到可销售库存里去,98 + 2 = 100。

积分服务也需要提供addCredit()接口的Cancel逻辑,将预增加积分字段的10个积分扣减掉。

仓储服务也需要提供一个saleDelivery()接口的Cancel逻辑,将销售出库单的状态修改为“CANCELED”设置为已取消。

然后这个时候,订单服务的TCC分布式事务框架只要感知到了任何一个服务的Try逻辑失败了,就会跟各个服务内的TCC分布式事务框架进行通信,然后调用各个服务的Cancel逻辑。

大家看看下面的图,直观的感受一下。

五、总结与思考

好了,兄弟们,聊到这儿,基本上大家应该都知道TCC分布式事务具体是怎么回事了!

总结一下,你要玩儿TCC分布式事务的话:首先需要选择某种TCC分布式事务框架,各个服务里就会有这个TCC分布式事务框架在运行。

然后你原本的一个接口,要改造为3个逻辑,Try-Confirm-Cancel

  • 先是服务调用链路依次执行Try逻辑

  • 如果都正常的话,TCC分布式事务框架推进执行Confirm逻辑,完成整个事务

  • 如果某个服务的Try逻辑有问题,TCC分布式事务框架感知到之后就会推进执行各个服务的Cancel逻辑,撤销之前执行的各种操作

这就是所谓的TCC分布式事务。

TCC分布式事务的核心思想,说白了,就是当遇到下面这些情况时,

  • 某个服务的数据库宕机了

  • 某个服务自己挂了

  • 那个服务的redis、elasticsearch、MQ等基础设施故障了

  • 某些资源不足了,比如说库存不够这些

先来Try一下,不要把业务逻辑完成,先试试看,看各个服务能不能基本正常运转,能不能先冻结我需要的资源。

如果Try都ok,也就是说,底层的数据库、redis、elasticsearch、MQ都是可以写入数据的,并且你保留好了需要使用的一些资源(比如冻结了一部分库存)。

接着,再执行各个服务的Confirm逻辑,基本上Confirm就可以很大概率保证一个分布式事务的完成了。

那如果Try阶段某个服务就失败了,比如说底层的数据库挂了,或者redis挂了,等等。

此时就自动执行各个服务的Cancel逻辑,把之前的Try逻辑都回滚,所有服务都不要执行任何设计的业务逻辑。保证大家要么一起成功,要么一起失败

写到这里,本文差不多该结束了。等一等,你有没有想到一个问题?

如果有一些意外的情况发生了,比如说订单服务突然挂了,然后再次重启,TCC分布式事务框架是如何保证之前没执行完的分布式事务继续执行的呢?

所以,TCC事务框架都是要记录一些分布式事务的活动日志的,可以在磁盘上的日志文件里记录,也可以在数据库里记录。保存下来分布式事务运行的各个阶段和状态。

问题还没完,万一某个服务的Cancel或者Confirm逻辑执行一直失败怎么办呢?

那也很简单,TCC事务框架会通过活动日志记录各个服务的状态。

举个例子,比如发现某个服务的Cancel或者Confirm一直没成功,会不停的重试调用他的Cancel或者Confirm逻辑,务必要他成功!

当然了,如果你的代码没有写什么bug,有充足的测试,而且Try阶段都基本尝试了一下,那么其实一般Confirm、Cancel都是可以成功的!

最后,再给大家来一张图,来看看给我们的业务,加上分布式事务之后的整个执行流程:

不少大公司里,其实都是自己研发TCC分布式事务框架的,专门在公司内部使用,比如我们就是这样。

不过如果自己公司没有研发TCC分布式事务框架的话,那一般就会选用开源的框架。

这里笔者给大家推荐几个比较不错的框架,都是咱们国内自己开源出去的:ByteTCC,tcc-transaction,himly

大家有兴趣的可以去他们的github地址,学习一下如何使用,以及如何跟Spring Cloud、Dubbo等服务框架整合使用。

只要把那些框架整合到你的系统里,很容易就可以实现上面那种奇妙的TCC分布式事务的效果了。

朋友,别告诉我你懂分布式事务!相关推荐

  1. 分布式事务详解【分布式事务的几种解决方案】彻底搞懂分布式事务

    文章目录 一.基本概念 什么是事务 本地事务 分布式事务 分布式事务产生的场景 二.分布式事务基础理论 CAP理论 CP - Consistency/Partition Tolerance AP - ...

  2. 6 张图带你彻底搞懂分布式事务 XA 模式

    作者 | 朱晋君 来源 | 阿里巴巴云原生公众号 XA 协议是由 X/Open 组织提出的分布式事务处理规范,主要定义了事务管理器 TM 和局部资源管理器 RM 之间的接口.目前主流的数据库,比如 o ...

  3. 事务连接中断_一文搞懂分布式事务-CAP理论

    互联网系统中,分布式事务是无法避免的,目前多数解决方案是BASE理论,最终一致性,结合事务补偿. 1.什么是CAP理论. CAP理论,又称为布鲁尔定理,是加州大学伯克利分校的计算机科学家埃里克.布鲁尔 ...

  4. 一篇文章彻底搞懂“分布式事务”

    在如今的分布式盛行的时代,分布式事务永远都是绕不开的一个话题,今天就谈谈分布式事务相关的一致性与实战解决方案. 01 为什么需要分布式事务 由于近十年互联网的发展非常迅速,很多网站的访问越来越大,集中 ...

  5. 25 张图,1.4 w字!彻底搞懂分布式事务原理

    本文提纲如下: 0. 前言 1. 单数据源事务 & 多数据源事务 2. 常见分布式事务解决方案 2.1. 分布式事务模型 2.2. 二将军问题和幂等性 2.3. 两阶段提交(2PC) & ...

  6. 【微服务入门】分布式事务详解及seata的使用

    一文读懂分布式事务 微服务中的分布式事务问题 1 分布式事务介绍 1.1 什么是事务 1.2 本地事务 1.3 什么是分布式事务 1.3.0 假如没有分布式事务 1.4 分布式事务系统架构 1.4.1 ...

  7. 阿里P8架构师谈:分布式事务的解决方案,以及原理、总结

    分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在这几年越来越火的微服务架构中,几乎可以说是无法避免,本文就围绕分布式事务各方面与大家进行介绍. 事务 1. ...

  8. 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务

    搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...

  9. mysql xa 和普通事务_一文看懂MySQL中基于XA实现的分布式事务

    概述 前面已经介绍了2PC和3PC方面的内容,那么MySQL数据库在分布式事务这块又是怎么规划呢? XA事务简介 XA 事务的基础是两阶段提交协议.需要有一个事务协调者来保证所有的事务参与者都完成了准 ...

最新文章

  1. yii权限rbac验证三张表字段说明
  2. 面向行人重识别的局部特征研究进展、挑战与展望
  3. python与excel的关系-使用python对excle和json互相转换的示例
  4. vba编程把纯文本转换成html,如何在Excel的单元格中将HTML转换为文本?
  5. Magento教程 20:仅限会员留言的产品评论设定!
  6. 8 stark组件 展示数据
  7. 项目管理中工时计算的问题
  8. Oracle 中给表添加主键、外键
  9. 计算机多媒体应用软件有超媒体特点吗,《多媒体技术与应用》(本)阶段练习一...
  10. mysql 全文搜索怎么设置_mysql 全文搜索 技巧
  11. PowerDesigner下载地址
  12. 【听课笔记】复旦大学遗传学_10肿瘤遗传学
  13. 科技「垦荒」,AI护虎
  14. TAGE Branch Predictor/分支预测
  15. python产品质量分析报告范文_Python Jinja2 徒手生成数据分析报告
  16. Java程序员常用的各种快捷键和命令
  17. 手机停机照样可以上网,,教教你。。
  18. anthony1314的小笔记
  19. 夜神模拟器怎么开脚本?
  20. 十二、构建一个基本的组合导航系统

热门文章

  1. 【Accelerated C++】重点回顾
  2. Machine Learning week 3 quiz : Regularization
  3. Matlab回显语句
  4. 第6周第4课:复习及扩展知识
  5. @ConfigurationProperties 注解
  6. JQuery 判断checkbox是否选中,checkbox全选,获取checkbox选中值
  7. 大四Java复习笔记之Java基础
  8. 五十八种网络故障及其解决办法
  9. 基于FFmpeg H264 + G711A 音视频裸流合并 MP4文件 ( G711A 转 AAC)
  10. 在一台服务器绑定多个IP