什么是TCC?

2023-05-16

假设现在有一个电商系统,里面有一个支付订单的场景,那对一个订单支付之后,我们需要做下面的步骤

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

  • 扣减商品库存

  • 给会员增加积分

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

业务场景有了,现在要更进一步,实现一个 TCC 分布式事务的效果,也就是说,订单服务 - 修改订单状态,库存服务 - 扣减库存,积分服务 - 增加积分,仓储服务 - 创建销售出库单,上述这几个步骤,要么一起成功,要么一起失败,必须是一个整体性的事务

举个例子,现在订单的状态都修改为 “已支付” 了,结果库存服务扣减库存失败。那个商品的库存原来是 100 件,现在卖掉了 2 件,本来应该是 98 件了。由于库存服务操作数据库异常,导致库存数量还是 100。当然不能允许这种情况发生了

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

有必要使用 TCC 分布式事务机制来保证各个服务形成一个整体性的事务。上面那几个步骤,要么全部成功,如果任何一个服务的操作失败了,就全部一起回滚,撤销已经完成的操作

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

1、TCC 实现阶段一:Try

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

首先,上面那个订单服务先把自己的状态修改为: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 操作,都执行成功了,这个时候,就需要依靠 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 分布式事务框架在运行。然后你原本的一个接口,要改造为 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 都是可以成功的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是TCC? 的相关文章

  • Marvell交换芯片88E6321/88E6320驱动总结-寄存器篇

    由于我在项目中将该芯片作为PHY和SERDES使用 xff0c 因此本文内容主要还是围绕PHY和SERDES的相关功能 xff0c 至于其他功能则没有进行深入研究 工作模式 在之前的硬件篇中有提到 xff0c 该芯片有两种寻址模式 xff1
  • 更新 O-ComTool V2.1.0 串口调试助手

    FBI再次WARNING 测试时间较短 xff0c 有问题留言反馈哟 xff01 本次更新如下 实现更加人性化的暂停显示 上一版本中 xff0c 点击暂停显示时间过久 xff0c 就会出现卡顿的现象 xff0c 现在舍弃原来的方法 xff0
  • 什么是PN结

    FBI WARNING xff1a 本文是个人对PN结的理解 xff0c 若有错误 xff0c 望不吝赐教 xff0c 谢谢 xff01 二极管 三极管作为电路中的常见元件 xff0c 了解其工作原理是非常必要的 xff0c 但是在此之前
  • struct termios结构体详解

    一 数据成员 termios 函数族提供了一个常规的终端接口 xff0c 用于控制非同步通信端口 这个结构包含了至少下列成员 xff1a tcflag t c iflag 输入模式 tcflag t c oflag 输出模式 tcflag
  • PISSTV 树莓派慢扫描电视

    连接硬件 硬件 xff1a 树莓派 有驱动的摄像头 调试时需要usb wifi 配置树莓派 配置树莓派时要开启树莓派摄像头的支持 因为需要安装软件 xff0c 将树莓派连接到外网 测试摄像头拍照 使用raspistill命令进行拍照 ras
  • PID控制参数整定(调节方法)原理+图示+MATLAB调试

    序 首先最重要的是了解每个参数调节了系统响应的那些属性 xff0c 通过观察响应从而调节参数改变属性 PID的作用概述 xff1a 1 P产生响应速度和力度 xff0c 过小响应慢 xff0c 过大会产生振荡 xff0c 是I和D的基础 2
  • 关于VSCODE的插件 一

    官方API文档 1 要学好TypeScript 官方教程 1 1TypeScript是一门弱类型语言 强类型和弱类型主要是站在变量类型处理的角度进行分类的 这些概念未经过严格定义 xff0c 它们并不是属于语言本身固有的属性 xff0c 而
  • Pixhawk学习1——CMakeList.txt的解析

    在PX4的工程文件中 xff0c src modules下是具体的飞控代码 里面主要包含了传感器采集 姿态结算 姿态控制 xff0c 位置结算 位置控制等程序模块 在进行二次开发时 xff0c 需要添加的模块也是在这个文件夹里 每个文件夹里
  • Pixhawk学习2——uORB微对象请求代理及规则

    在Pixhawk中 xff0c 所有的功能被独立以进程模块为单位进行实现并工作 而每个进程模块都有一个 xff08 或多个 xff1f xff09 主题信息topic xff08 topic可以在Firmware msg里查看到所有的可使用
  • Pixhawk学习4——Commander相关分析

    Commander文件夹中的内容的作用主要为Pixhawk飞行模式的切换 该段程序会根据遥控器上的开关状态以及飞机飞行状态和各传感器性能状态进行判断 xff0c 最终实现飞行模式的切换 飞行模式切换主要涉及到以下几个文件 xff1a src
  • Pixhawk学习7——位置解算

    Pixhawk的位置解算分为两部分 xff0c 第一部分主要为传感器的数据获取 xff0c 而该部分最主要的就是GPS数据的提取 第二部分为与惯性器件之间的组合导航 组合导航的好处我就不用多说了 Pixhawk代码中目前主要有两处组合导航的
  • Pixhawk学习9——固定翼位置控制(L1控制+TECS总能量控制)

    本篇博客本来没有在之前的计划中 但由于最近项目上遇到了固定翼轨迹控制的一些问题 xff0c 所以就结合pix的程序学习总结了一下 不同于旋翼 xff0c 固定翼要实现位置变化必须得有一个轨迹变化过程 xff0c 因为它不像旋翼那样可以直接调
  • Pixhawk学习10.2——多旋翼位置控制

    10 1中介绍了目标位置点的计算逻辑 xff0c 知道下一时刻的目标位置后 xff0c 飞控需要根据当前位置进行计算 xff0c 依次得到期望速度 xff0c 期望拉力矢量 xff0c 期望姿态 至此就完成了多旋翼的位置控制 1 期望速度计

随机推荐

  • Http权威指南笔记(三)——HTTP报文

    前面介绍了URL是用于定位服务器上的资源 但是定位到资源后 xff0c 通过什么样的方式 规定来让客户端和服务端进行交流呢 xff1f 这就是本篇要介绍的HTTP报文 1 报文流 HTTP 报文是在 HTTP 应用程序之间发送的数据块 这些
  • 卡尔曼滤波算法详细推导

    一 预备知识 1 协方差矩阵 是一个维列向量 xff0c 是的期望 xff0c 协方差矩阵为 可以看出 协方差矩阵都是对称矩阵且是半正定的 协方差矩阵的迹是的均方误差 2 用到的两个矩阵微分公式 公式一 xff1a 公式二 xff1a 若是
  • 超声波测距实验

    超声波测距实验 超声波发射器向某一方向发射超声波 xff0c 在发射的同时开始计时 xff0c 超声波在空气中传播 xff0c 途中碰到障碍物就立即返回来 xff0c 超声波接收器收到反射波就立即停止计时 声波在空气中的传播速度为340m
  • Win7+Ubuntu双系统安装教程

    一 安装Win7 xff08 采用WinPE 43 gho xff09 1 设置笔记本电脑的BIOS xff0c 因为是安装win7 xff0c 最好采用Legacy模式 xff0c UEFI模式和win8 win10等以后的操作系统适配的
  • C语言——switch....case函数用法

    switch case函数用法 include lt stdio h gt int main int data char cdata printf 34 请输入一个数字 n 34 scanf 34 d 34 amp data switch
  • 计算机组成原理4(程序查询方式、程序中断方式、DMA方式及其I/O接口电路)

    文章目录 一 程序查询方式二 程序中断方式三 DMA方式 一 程序查询方式 1 程序查询方式的接口电路 2 符号说明 amp 与非门B工作触发器D完成触发器 3 程序查询工作过程 xff08 输入 xff09 xff08 1 xff09 当
  • FreeRTOS队列创建、发送和接收(备忘)

    目录 一 简介 1 1 开发环境 1 2 功能说明 二 动态创建队列 2 1 头文件声明 2 2 工程文件定义 2 3 创建队列 三 静态创建队列 3 1 头文件声明 3 2 工程文件定义 3 3 创建队列 四 写入消息 4 1 定义缓存变
  • 自动化面试题2

    一 画出 集电极开路 电压输出 互补输出 线性驱动输出 原理图 二 二进制 八进制 十进制以及十六进制之间的转化 三 PLC是什么 xff0c 并简述其优点和缺点 可编程控制器 xff08 Programmable Logic Contro
  • 【教程】win10 固态硬盘卡机卡死卡顿的真正原因!

    本人自从换了win10以后从来没卡过的电脑反正就是频繁的卡顿 xff0c 卡死 我试过以下方法 xff0c 有人说是微软拼音输入法的问题 xff0c 我直接更换了输入法 xff0c 这个效果是有 xff0c 卡机的频率降低了 xff0c 但
  • SizeChanged事件

    SizeChanged事件有的人不成功 xff0c 我也不知道什么原因不成功 xff0c 贴一下我成功的样子 xff01 xff01 xff01 Designer cs文件Form最下面放这个 this SizeChanged 43 61
  • centos7 安装docker

    sudo yum config manager add repo http mirrors aliyun com docker ce linux centos docker ce repo 出现以下内容则表示docker仓库配置成功 xff
  • 项目管理之启动:识别项目中的四类干系人

    干系人分析 指对项目干系人进行分析和归类 xff0c 有针对性地规划管理其核心诉求和期望 xff0c 让干系人可以更好地参与项目 xff0c 对项目产生积极影响 xff0c 从而更好地保障项目目标的成功达成 干系人分析的目的是什么呢 xff
  • 公平锁和非公平锁介绍,为什么要“非公平”?

    什么是公平和非公平 公平锁指的是按照线程请求的顺序 xff0c 来分配锁 xff1b 而非公平锁指的是不完全按照请求的顺序 xff0c 在一定情况下 xff0c 可以允许插队 但需要注意这里的非公平并不是指完全的随机 xff0c 不是说线程
  • 什么是自旋锁?自旋的好处和后果是什么呢?

    什么是自旋 自旋 可以理解为 自我旋转 xff0c 这里的 旋转 指 循环 xff0c 比如 while 循环或者 for 循环 自旋 就是自己在这里不停地循环 xff0c 直到目标达成 而不像普通的锁那样 xff0c 如果获取不到锁就进入
  • Bluez去掉绝对音量支持

    修改bluez 5 37中 profiles audio avrcp c 去掉改支持AVRCP EVENT VOLUME CHANGED 3816 session gt supported events 61 3817 1 lt lt AV
  • 为何每次用完 ThreadLocal 都要调用 remove()?——内存泄漏

    什么是内存泄漏 内存泄漏指的是 xff0c 当某一个对象不再有用的时候 xff0c 占用的内存却不能被回收 xff0c 这就叫作内存泄漏 因为通常情况下 xff0c 如果一个对象不再有用 xff0c 那么我们的垃圾回收器 GC xff0c
  • CountDownLatch 是如何安排线程执行顺序的?

    CountDownLatch xff0c 它是 JDK 提供的并发流程控制的工具类 xff0c 它是在 java util concurrent 包下 xff0c 在 JDK1 5 以后加入的 比如我们去游乐园坐激流勇进 xff0c 有的时
  • 发生死锁必须满足哪 4 个条件?

    要想发生死锁有 4 个缺一不可的必要条件 第 1 个叫互斥条件 xff0c 它的意思是每个资源每次只能被一个线程 xff08 或进程 xff0c 下同 xff09 使用 xff0c 为什么资源不能同时被多个线程或进程使用呢 xff1f 这是
  • 红黑树和二叉树有什么区别?

    红黑树和二叉树有什么区别 xff1f 什么是二叉树 xff1f 什么是红黑树 xff1f 二叉树 xff08 Binary Tree xff09 是指每个节点最多只有两个分支的树结构 xff0c 即不存在分支大于 2 的节点 xff0c 二
  • 什么是TCC?

    假设现在有一个电商系统 xff0c 里面有一个支付订单的场景 xff0c 那对一个订单支付之后 xff0c 我们需要做下面的步骤 更改订单的状态为 已支付 扣减商品库存 给会员增加积分 创建销售出库单通知仓库发货 业务场景有了 xff0c