原文网址:分布式事务--TCC--流程/原理_IT利刃出鞘的博客-CSDN博客

简介

本文介绍TCC分布式事务解决方案的流程及原理。

流程

详解

业务操作分两阶段完成

如下图所示,接入TCC前,业务操作只需要一步就能完成,但是在接入TCC之后,需要考虑如何将其分成2阶段完成,把资源的检查和预留放在一阶段的Try操作中进行,把真正的业务操作的执行放在二阶段的Confirm操作中进行;

要保证第一阶段Try操作成功之后,二阶段Confirm操作一定能成功;

幂等控制

无论是网络数据包重传,还是异常事务的补偿执行,都会导致TCC服务的Try、Confirm或者Cancel操作被重复执行。用户在实现TCC服务时,需要考虑幂等控制,即Try、Confirm、Cancel 执行一次和执行多次的业务结果是一样的。

confirm的重复执行

A服务调用B服务,这两个服务都有TCC接口。若这两个服务try都成功了,然后A的服务confirm成功,而B的confirm失败,则TCC框架会重试所有confirm(即:A的confirm和B的confirm)

cancel的重复执行

场景1:服务A的cancel成功,B的cancel失败,则会重试A和B的cancel。

场景2:任一服务try发生了异常,则直接调用cancel。

允许空回滚

如下图所示,事务协调器在调用TCC服务的一阶段Try操作时,可能会出现因为丢包而导致的网络超时,此时事务协调器会触发二阶段回滚,调用TCC服务的Cancel操作;

TCC服务在未收到Try请求的情况下收到Cancel请求,这种场景被称为空回滚;TCC服务在实现时应当允许空回滚的执行;

防悬挂控制

如下图所示,事务协调器在调用TCC服务的一阶段Try操作时,可能会出现因网络拥堵而导致的超时,此时事务协调器会触发二阶段回滚,调用TCC服务的Cancel操作;在此之后,拥堵在网络上的一阶段Try数据包被TCC服务收到,出现了二阶段Cancel请求比一阶段Try请求先执行的情况;

用户在实现TCC服务时,应当允许空回滚,但是要拒绝执行空回滚之后到来的一阶段Try请求;

业务数据可见性控制

TCC服务的一阶段Try操作会做资源的预留,在二阶段操作执行之前,如果其他事务需要读取被预留的资源数据,那么处于中间状态的业务数据该如何向用户展示,需要业务在实现时考虑清楚;通常的设计原则是“宁可不展示、少展示,也不多展示、错展示”;

并发访问控制

TCC服务的一阶段Try操作预留资源之后,在二阶段操作执行之前,预留的资源都不会被释放;如果此时其他分布式事务修改这些业务资源,会出现分布式事务的并发问题。

用户在实现 TCC 时,应当考虑并发性问题,将锁的粒度降到最低,以最大限度的提高分布式事务的并发性。

示例

以下还是以A账户扣款为例,“账户 A 上有 100 元,事务 T1 要扣除其中的 30 元,事务 T2 也要扣除 30 元,出现并发”。

在一阶段 Try 操作中,分布式事务 T1 和分布式事务 T2 分别冻结资金的那一部分资金,相互之间无干扰;这样在分布式事务的二阶段,无论 T1 是提交还是回滚,都不会对 T2 产生影响,这样 T1 和 T2 在同一笔业务数据上并行执行。

业务场景示例

概述

流程详解   //以购买商品为例(生成订单、减库存)。

Try

下单业务由订单服务和库存服务协同完成,在try阶段订单服务和库存服务完成检查和预留资源。

订单服务:检查当前是否满足提交订单的条件(比如:当前存在未完成订单的不允许提交新订单)。
库存服务:检查当前是否有充足的库存,并锁定资源。

Confirm

订单服务和库存服务成功完成Try后开始正式执行资源操作。

订单服务:向订单写一条订单信息。
库存服务:减去库存。

Cancel

如果订单服务和库存服务有一方出现失败则全部取消操作。

订单服务:删除新增的订单信息。
库存服务:减去的库存再还原。

举个简单的例子:用100元买一瓶水,

  1. Try阶段:你需要向你的钱包检查是否够100元并锁住这100元,水也是一样的。
  2. confirm:写订单信息、减库存
  3. 若有一个失败,则cancel(释放这100元和这一瓶水)。若cancel失败不论什么失败都进行重试cancel,所以要幂等。
  4. 如果都成功,则进行confirm:确认这100元被扣、这一瓶水被卖,如果confirm失败无论什么失败则重试(会依靠活动日志进行重试)

伪代码

TCC阶段1:try

订单服务

public class OrderService {// 库存服务@Autowiredprivate InventoryService inventoryService;// 积分服务@Autowiredprivate CreditService creditService;// 仓储服务@Autowiredprivate WmsService wmsService;// 对这个订单完成支付public void pay(){//对本地的的订单数据库修改订单状态为"已支付"orderDAO.updateStatus(OrderStatus.PAYED);//调用库存服务扣减库存inventoryService.reduceStock();//调用积分服务增加积分creditService.addCredit();//调用仓储服务通知发货wmsService.saleDelivery();}
}

其实就是订单服务完成本地数据库操作之后,通过 Spring Cloud 的 Feign 来调用其他的各个服务罢了。

但是光是凭借这段代码,是不足以实现 TCC 分布式事务,需要对这个订单服务进行修改。

1.检查订单/修改订单状态

检查是否有未付款的订单,如果

首先,上面那个订单服务先检查是否先把自己的状态修改为:OrderStatus.UPDATING。
        这是啥意思呢?也就是说,在 pay() 那个方法里,你别直接把订单状态修改为已支付啊!你先把订单状态修改为 UPDATING,也就是修改中的意思。
        这个状态是个没有任何含义的这么一个状态,代表有人正在修改这个状态罢了。

2.冻结库存

库存服务直接提供的那个 reduceStock() 接口里,也别直接扣减库存啊,你可以是冻结掉库存。
        举个例子,本来你的库存数量是 100,你别直接 100 - 2 = 98,扣减这个库存!
        你可以把可销售的库存:100 - 2 = 98,设置为 98 没问题,然后在一个单独的冻结库存的字段里,设置一个 2。也就是说,有 2 个库存是给冻结了。

3.预增积分

积分服务的 addCredit() 接口也是同理,别直接给用户增加会员积分。你可以先在积分表里的一个预增加积分字段加入积分。
        比如:用户积分原本是 1190,现在要增加 10 个积分,别直接 1190 + 10 = 1200 个积分啊!
        你可以保持积分为 1190 不变,在一个预增加字段里,比如说 prepare_add_credit 字段,设置一个 10,表示有 10 个积分准备增加。

4.预创建出库单

仓储服务的 saleDelivery() 接口也是同理啊,你可以先创建一个销售出库单,但是这个销售出库单的状态是“UNKNOWN”。
        也就是说,刚刚创建这个销售出库单,此时还不确定它的状态是什么呢!

上面这套改造接口的过程,其实就是所谓的 TCC 分布式事务中的第一个 T 字母代表的阶段,也就是 Try 阶段。
        总结上述过程,如果你要实现一个 TCC 分布式事务,首先你的业务的主流程以及各个接口提供的业务含义,不是说直接完成那个业务操作,而是完成一个 Try 的操作。
        这个操作,一般都是锁定某个资源,设置一个预备类的状态,冻结部分数据,等等,大概都是这类操作。
        咱们来一起看看下面这张图,结合上面的文字,再来捋一捋整个过程:

TCC阶段2:confirm

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

如果你在各个服务里引入了一个 TCC 分布式事务的框架,订单服务里内嵌的那个 TCC 分布式事务框架可以感知到各个服务的 Try 操作都成功了。此时,TCC 分布式事务框架会控制进入 TCC 下一个阶段,第一个 C 阶段,也就是 Confirm 阶段。
        为了实现这个阶段,你需要在各个服务里再加入一些代码。比如说,订单服务里,你可以加入一个 Confirm 的逻辑,就是正式把订单的状态设置为“已支付”了,大概是类似下面这样子

public class OrderServiceConfirm {public void pay(){orderDao.updateStatus(OrderStatus.PAYED);}
}

1.库存服务

库存服务也是类似的,你可以有一个 InventoryServiceConfirm 类,里面提供一个 reduceStock() 接口的 Confirm 逻辑,这里就是将之前冻结库存字段的 2 个库存扣掉变为 0。
        这样的话,可销售库存之前就已经变为 98 了,现在冻结的 2 个库存也没了,那就正式完成了库存的扣减。

2.积分服务

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

3.仓储服务

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

上面各种服务的 Confirm 的逻辑都实现好了,一旦订单服务里面的 TCC 分布式事务框架感知到各个服务的 Try 阶段都成功了以后,就会执行各个服务的 Confirm 逻辑。
        订单服务内的 TCC 事务框架会负责跟其他各个服务内的 TCC 事务框架进行通信,依次调用各个服务的 Confirm 逻辑。然后,正式完成各个服务的所有业务逻辑的执行。
        同样,给大家来一张图,顺着图一起来看看整个过程:

TCC阶段3:cancel

举个例子:在 Try 阶段,比如积分服务吧,它执行出错了,此时会怎么样?
        那订单服务内的 TCC 事务框架是可以感知到的,然后它会决定对整个 TCC 分布式事务进行回滚。
        也就是说,会执行各个服务的第二个 C 阶段,Cancel 阶段。同样,为了实现这个 Cancel 阶段,各个服务还得加一些代码。

1.订单服务

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

2.库存服务

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

3.积分服务

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

4.仓储服务

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

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

其他网址

分布式事物框架TCC-Transaction使用教程_varyall的专栏-CSDN博客

分布式事务之TCC事务丶Java教程网-IT开发者们的技术天堂
转:分布式事务之TCC服务设计和实现注意事项 - Ryana - 博客园

TCC 理论及设计实现指南介绍 · SOFAStack

分布式事务之-TCC服务设计与实现一_Alen-CSDN博客
TCC和两阶段分布式事务处理的区别_轰鸣-CSDN博客

终于有人把“TCC分布式事务”实现原理讲明白了! - JaJian - 博客园

分布式事务--TCC--流程/原理相关推荐

  1. 阿里分布式事务框架Seata原理解析

    阿里分布式事务框架Seata原理解析 作者:伊凡的一天 链接:https://www.jianshu.com/p/044e95223a17 Seata框架是一个业务层的XA(两阶段提交)解决方案.在理 ...

  2. 分布式事务解决方案和原理

    分布式事务解决方案和原理 一. 背景: 我们知道, 在以前的 all-in-one 的项目开发模式下, 所有事务问题都是本地事务问题, 基本上利用mysql的优化方案和java提供的API, 可以解决 ...

  3. 【网站架构】一招搞定90%的分布式事务,实打实介绍数据库事务、分布式事务的工作原理应用场景

    大家好,欢迎来到停止重构的频道.本期,我们来聊一下数据库事务以及分布式事务. 大家都在强调事务的重要性,而分布式事务也说是微服务必备的.但又说事务会影响性能,分布式事务更是很复杂的东西.使得大家都很迷 ...

  4. 分布式事务框架Seata原理详解

    本文来深度解析下分布式事务框架Seata原理,知其然知其所以然. 文章目录 Seata概述 什么是2PC二阶段提交协议 MySQL XA方案 Seata核心知识 Seata设计目标 Seata组成结构 ...

  5. mysql2阶段提交具体实现_ShardingSphere 4.x 分布式事务之实现原理

    导览 本小节主要介绍ShardingSphere分布式事务的实现原理 两阶段XA事务 Seata柔性事务 两阶段事务-XA 实现原理 实现原理 ShardingSphere里定义了分布式事务的SPI接 ...

  6. Redis分布式事务锁的原理(上)

    我们在单机服务器,出现资源的竞争,一般使用synchronized 就可以解决,但是在分布式的服务器上,synchronized 就无法解决这个问题,这就需要一个分布式事务锁. 除此之外面试,基本会问 ...

  7. 分布式事务架构设计原理

    随着业务需求的复杂化,企业应用规模不断扩大,在后端开发中经常会遇到以下问题: 业务的并发要求非常高,对应的业务需要通过微服务拆分,甚至分库分表等架构设计才能满足并发需求,此时业务操作无法在同一个数据库 ...

  8. TCC分布式事务的实现原理

    目录 一.写在前面 二.业务场景介绍 三.进一步思考 四.落地实现TCC分布式事务 (1)TCC实现阶段一:Try (2)TCC实现阶段二:Confirm (3)TCC实现阶段三:Cancel 五.总 ...

  9. 分布式事务——TCC 原理

    概念 TCC 又称补偿事务.其核心思想是: " 针对每个操作都要注册一个与其对应的确认和补偿(撤销)操作 ".它分为三个操作: Try 阶段:主要是对业务系统做检测及资源预留. C ...

最新文章

  1. cytoscape绘图互作网络图(二)
  2. Linux TOP 交互命令
  3. CSP认证201803-1 跳一跳[C++题解]: 模拟
  4. 视觉研究的前世今生(中)王天珍(武汉理工大学)
  5. 理科生浪漫起来,谁都顶不住!
  6. ICCV2021 |优胜劣汰,MIT团队提出自适应多模态选取框架用于视频理解
  7. git 常见问题的解决方案
  8. 小宝宝即将来到这个世界,希望迎接他的是大家的祝福
  9. r 语言初学者指南_阻止自然语言处理的初学者指南
  10. python spss stata_零基础的文科生怎么学习python.stata.spss.r等软件?
  11. PDA扫描 Geenk scan 的方法列表
  12. 【EXLIBRIS】#小词旮旯# 004 Camera
  13. w3c怎么检测html5,HTML5教程:html标签属性通过w3c验证
  14. Ubuntu18.04 + win10 双系统,grub引导配置,美化
  15. 计算机实战项目之 [含论文+辩论PPT+源码等]微信小程序社区疫情防控+后台管理|前后分离VUE[包运行成功
  16. 有房间匹配和无房间匹配
  17. 括号配对检测python123_括的拼音_括组词_括意思(解释)-常用汉字大全
  18. Unity最简单的消息中心
  19. 什么是奇异值分解(SVD)?
  20. 逻辑回归优化算法总结一

热门文章

  1. 运行python脚本卡住_为什么我的 Python 程序卡住啦!
  2. 手机音频口反向列表 类Square手机刷卡器注意事项
  3. VSCode配置JAVA开发环境windows 2020
  4. 一只小白的代码之路 15.9.1~15.10.18
  5. linux防火墙(firewalld和iptables)
  6. python玩卡_用 Python 自动玩王者荣耀,简直太秀了!
  7. 浅谈浏览器的兼容性(从HTML、CSS、JS、PC端、移动端等方面)
  8. 3D建模:0基础如何学习建模及行业应用范围
  9. linux图形方式的运行级定义为,在大多数 Linux 发行版本中,图形方式的运行级定义为?...
  10. 群智能算法应用第一期--SSA算法应用于机器人路径规划