图解分布式事务实现原理(二)

参考

本文参考https://zhuanlan.zhihu.com/p/648556608,在小徐的基础上做了个人的笔记。


TCC 实现方案

TCC 概念简述

TCC(Try-Confirm-Cancel)是一种分布式事务处理模式,旨在保证分布式系统中的事务一致性。它的核心思想是将一个分布式事务分解为多个子事务,每个子事务都有三个关键操作

  • Try:在Try阶段,子事务尝试执行业务检查、资源预留和其他必要的前置操作,以准备好执行实际的业务。如果Try操作成功,表示可以继续执行后续的Confirm操作。

  • Confirm:在Confirm阶段,子事务执行实际的业务确认操作,将之前预留的资源实际分配,完成业务处理。只有当所有分支事务的Try操作都成功,并且TM发起Confirm操作时,才会真正确认事务的执行。

  • Cancel:在Cancel阶段,子事务执行与Try操作相反的操作,即回滚操作,用于撤销之前的资源预留和业务处理。如果Try操作失败,TM将发起所有分支事务的Cancel操作。

**TCC的分布式事务管理器(TM)**首先发起所有分支事务的Try操作,如果有任何一个Try操作失败,TM将会发起所有分支事务的Cancel操作,以确保分布式事务的一致性。只有当所有分支事务的Try操作都成功时,TM才会发起所有分支事务的Confirm操作,最终完成整个事务的确认。

TCC模式通过将分布式事务拆解成多个子事务并明确Try、Confirm和Cancel操作,提供了更细粒度的事务控制,能够适应不同业务场景的需求。然而,实现TCC模式需要开发者谨慎处理异常、重试机制和分布式事务管理,因此具有一定的复杂性

分支事务成功的场景

在这里插入图片描述

分支事务失败的场景

在这里插入图片描述

TCC 宏观架构

下面是 TCC 分布式事务实现方案的整体架构,大家可以先整体浏览一下存个印象,下面我们会逐一展开介绍:

在这里插入图片描述

在 TCC 分布式事务架构中,包含三类角色:

  • 应用方 Application:指的是需要使用到分布式事务能力的应用方,即这套 TCC 框架服务的甲方
  • TCC 组件 TCC Component:指的是需要完成分布式事务中某个特定步骤的子模块. 这个模块通常负责一些状态数据的维护和更新操作,需要对外暴露出 Try、Confirm 和 Cancel 三个 API:
    • Try:锁定资源,通常以类似【冻结】的语义对资源的状态进行描述,保留后续变化的可能性
    • Confirm:对 Try 操作进行二次确认,将记录中的【冻结】态改为【成功】态
    • Cancel:对 Try 操作进行回滚,将记录中的【冻结】状消除或者改为【失败】态. 其底层对应的状态数据会进行回滚
  • 事务协调器 TX Manager:负责统筹分布式事务的执行:
  • 实现 TCC Component 的注册管理功能
  • 负责和 Application 交互,提供分布式事务的创建入口,给予 Application 事务执行结果的响应
  • 串联 Try -> Confirm/Cancel 的两阶段流程. 在第一阶段中批量调用 TCC Component 的 Try 接口,根据其结果,决定第二阶段是批量调用 TCC Component 的 Confirm 接口还是 Cancel 接口

TCC 案例分析

下面我们引入一个具体的分布式事务场景问题,并通过 TCC 架构加以实现,帮助大家进一步提高对 TCC 分布式事务方案的感性认识.

现在假设我们需要维护一个电商后台系统,需要处理来自用户的支付请求. 每当有一笔支付请求到达,我们需要执行下述三步操作,并要求其前后状态保持一致性:

  • 在订单模块中,创建出这笔订单流水记录
  • 在账户模块中,对用户的账户进行相应金额的扣减
  • 在库存模块中,对商品的库存数量进行扣减

上面这三步操作分别需要对接订单、账户、库存三个不同的子模块,底层的状态数据是基于不同的数据库和存储组件实现的,并且我们这套后台系统是基于当前流行的微服务架构实现的,这三子个模块本身对应的就是三个相互独立的微服务,因此如何实现在一笔支付请求处理流程中,使得这三笔操作对应的状态数据始终保持高度一致性,就成了一个非常具有技术挑战性的问题.

在这里插入图片描述

首先,我们基于 TCC 的设计理念,将订单模块、账户模块、库存模块分别改造成三个 TCC Component,每个 Component 对应需要暴露出 Try、Confirm、Cancel 三个 API,对应于冻结资源、确认更新资源、回滚解冻资源三个行为.

同时,为了能够简化后续 TX Manager 和 Application 之间的交互协议,每个 TCC Component 会以插件的形式提前注册到 TX Manager 维护的组件市场 Component Market 中,并提前声明好一个全局唯一键与之进行映射关联.

在这里插入图片描述
由于每个 TCC Component 需要支持 Try 接口的锁定操作,因此其中维护的数据需要在明细记录中拆出一个用于标识 “冻结” 状态的标签,或者在状态机中拆出一个 “冻结” 状态.

最终在第二阶段的 Confirm 或者 Cancel 请求到达时,再把 ”冻结“ 状态调整为 ”成功“ 或者 ”失败“ 的终态.

在这里插入图片描述
下面描述一下,基于 TCC 架构实现后,对应于一次支付请求的分布式事务处理流程:

  1. Application 调用 TX Manager 的接口,创建一轮分布式事务:
  2. Application 需要向 TX Manager 声明,这次操作涉及到的 TCC Component 范围,包括 订单组件、账户组件和库存组件
  3. Application 需要向 TX Manager 提前传递好,用于和每个 TCC Component 交互的请求参数( TX Manager 调用 Component Try 接口时需要传递)
  4. TX Manager 需要为这笔新开启的分布 式事务分配一个全局唯一的事务主键 Transaction ID
  5. TX Manager 将这笔分布式事务的明细记录添加到事务日志表中
  6. TX Manager 分别调用订单、账户、库存组件的 Try 接口,试探各个子模块的响应状况,比并尝试锁定对应的资源
  7. TX Manager 收集每个 TCC Component Try 接口的响应结果,根据结果决定下一轮的动作是 Confirm 还是 Cancel
  8. 倘若三笔 Try 请求中,有任意一笔未请求成功:
    • TX Manager 给予 Application 事务执行失败的 Response
    • TX Manager 批量调用订单、账户、库存 Component 的 Cancel 接口,回滚释放对应的资源
    • 在三笔 Cancel 请求都响应成功后,TX Manager 在事务日志表中将这笔事务记录置为【失败】状态
  9. 倘若三笔 Try 请求均响应成功了:
    • TX Manager 给予 Application 事务执行成功的 ACK
    • TX Manager 批量调用订单、账户、库存 Component 的 Confirm 接口,使得对应的变更记录实际生效
      在三笔 Confirm 请求都响应成功后,TX Manager 将这笔事务日志置为【成功】状态

在这里插入图片描述
在上述流程中,有一个很重要的环节需要补充说明,首先,TCC 本质上是一个两阶段提交(Two Phase Commitment Protocol,2PC)的实现方案,分为 Try 和 Confirm/Cancel 的两个阶段

  • Try 操作的容错率是比较高的,原因在于有人帮它兜底. Try 只是一个试探性的操作,不论成功或失败,后续可以通过第二轮的 Confirm 或 Cancel 操作对最终结果进行修正
  • Confirm/Cancel 操作是没有容错的,倘若在第二阶段出现问题,可能会导致 Component 中的状态数据被长时间”冻结“或者数据状态不一致的问题

针对于这个场景,TCC 架构中采用的解决方案是:在第二阶段中,TX Manager 轮询重试 + TCC Component 幂等去重. 通过这两套动作形成的组合拳,保证 Confirm/ Cancel 操作至少会被 TCC Component 执行一次.

首先,针对于 TX Manager 而言:

  • 需要启动一个定时轮询任务
  • 对于事务日志表中,所有未被更新为【成功/失败】对应终态的事务,需要摘出进行检查
  • 检查时查看其涉及的每个组件的 Try 接口的响应状态以及这笔事务的持续时长
  • 倘若事务应该被置为【失败】(存在某个 TCC Component Try 接口请求失败),但状态却并未更新,说明之前批量执行 Cancel 操作时可能发生了错误. 此时需要补偿性地批量调用事务所涉及的所有 Component 的 Cancel 操作,待所有 Cancel 操作都成功后,将事务置为【失败】状态
  • 倘若事务应该被置为【成功】(所有 TCC Component Try 接口均请求成功),但状态却并未更新,说明之前批量执行 Confirm 操作时可能发生了错误. 此时需要补偿性地批量调用事务所涉及的所有 Component 的 Confirm 操作,待所有 Confirm 操作都成功后,将事务置为【成功】状态
  • 倘若事务仍处于【进行中】状态(TCC Component Try 接口请求未出现失败,但并非所有 Component Try 接口都请求成功),则检查事务的创建时间,倘若其耗时过长,同样需要按照事务失败的方式进行处理

在这里插入图片描述
需要注意,在 TX Manager 轮询重试的流程中,针对下游 TCC Component 的 Confirm 和 Cancel 请求只能保证 at least once 的语义,换句话说,这部分请求是可能出现重复的.

因此,在下游 TCC Component 中,需要在接收到 Confirm/Cancel 请求时,执行幂等去重操作. 幂等去重操作需要有一个唯一键作为去重的标识,这个标识键就是 TX Manager 在开启事务时为其分配的全局唯一的 Transaction ID,它既要作为这项事务在事务日志表中的唯一键,同时在 TX Manager 每次向 TCC Component 发起请求时,都要携带上这笔 Transaction ID.

TX Manager 职责

首先针对于事务协调器 TX Manager,其核心要点包括:

  • 注册TCC Component接口:该接口用于向分布式事务框架注册TCC组件(Try、Confirm、Cancel组件),以便管理和执行事务。不同的应用程序可能有不同的TCC组件需求,因此需要提供接口来注册和管理这些组件。

  • 启动分布式事务接口:作为与应用程序交互的唯一入口,该接口用于启动分布式事务。应用程序通过调用此接口来触发分布式事务的执行,并根据事务的执行结果进行反馈。

  • 全局唯一的Transaction ID:每个分布式事务需要一个全局唯一的事务标识,通常称为Transaction ID,用于跟踪和管理事务。同时,需要一个事务日志表来记录每项分布式事务的执行进展明细,以便进行事务状态的管理和恢复。

  • 串联Try-Confirm/Cancel两阶段流程:TCC模式的核心是将事务分为Try、Confirm和Cancel三个阶段,需要实现这三个阶段的串联执行流程。根据Try的结果,推进执行Confirm或Cancel流程,以确保事务的一致性。

  • 持续运行轮询检查任务:为了确保分布式事务的最终一致性,需要持续运行轮询检查任务,监测每个处于中间态的分布式事务,并将其推进到终态(已确认或已取消)。这有助于处理各种异常情况和故障恢复。

在这里插入图片描述

TCC Component 职责

在这里插入图片描述

对于 TCC Component 而言,其需要关心和处理的工作包括:

  • 暴露出 Try、Confirm、Cancel 三个入口,对应于 TCC 的语义
  • 针对数据记录,新增出一个对应于 Try 操作的中间状态枚举值
  • 针对于同一笔事务的重复请求,需要执行幂等性校验
  • 需要支持空回滚操作. 即针对于一笔新的 Transaction ID,在没收到 Try 的前提下,若提前收到了 Cancel 操作,也需要将这个信息记录下来,但不需要对真实的状态数据发生变更

下面针对最后一点提到的空回滚操作,进一步加以说明:

这个空回滚机制本质上是为了解决 TCC 流程中出现的悬挂问题,下面我们举个具体例子加以说明:

具体来说,如果TX Manager在向Component A发起Try请求时发生了超时,并且TX Manager已经批量执行了Cancel操作,然后之前由于网络问题而阻塞的Try请求到达了Component A,这可能导致请求到达的次序颠倒。在这种情况下,Component A需要确保只要接收到了对应的Cancel请求,之后到来的Try请求需要被忽略,以维护事务的一致性。

支持空回滚操作是TCC组件的一项关键功能。通过空回滚操作,即使Try请求到达的次序发生颠倒,Component A仍然可以正确处理事务。当Component A收到Cancel请求时,它可以标记相应的事务为已取消状态,并且在之后收到的Try请求到达时,可以忽略它们,因为事务已经被取消。

这种机制确保了TCC事务模式的鲁棒性,即使在不稳定的网络环境下,也能够维护事务的一致性。空回滚操作是一种有效的方式来处理请求到达顺序的问题,确保分布式事务的可靠性。

在这里插入图片描述

TCC 优劣势分析

最后我们针对 TCC 分布式事务实现方案的优劣势进行分析:

优势:

  • TCC 可以称得上是真正意义上的分布式事务:任意一个 Component 的 Try 操作发生问题,都能支持事务的整体回滚操作
  • TCC 流程中,分布式事务中数据的状态一致性能够趋近于 100%,这是因为第二阶段 Confirm/Cancel 的成功率是很高的,原因在于如下三个方面:
    • TX Manager 在此前刚和 Component 经历过一轮 Try 请求的交互并获得了成功的 ACK,因此短时间内,Component 出现网络问题或者自身节点状态问题的概率是比较小的
    • TX Manager 已经通过 Try 操作,让 Component 提前锁定了对应的资源,因此确保了资源是充分的,且由于执行了状态锁定,出现并发问题的概率也会比较小
    • TX Manager 中通过轮询重试机制,保证了在 Confirm 和 Cancel 操作执行失败时,也能够通过重试机制得到补偿

劣势:

  • TCC 分布式事务中,涉及的状态数据变更只能趋近于最终一致性,无法做到即时一致性
  • 事务的原子性只能做到趋近于 100%,而无法做到真正意义上的 100%,原因就在于第二阶段的 Confirm 和 Cancel 仍然存在极小概率发生失败,即便通过重试机制也无法挽救. 这部分小概率事件,就需要通过人为介入进行兜底处理
  • TCC 架构的实现成本是很高的,需要所有子模块改造成 TCC 组件的格式,且整个事务的处理流程是相对繁重且复杂的. 因此在针对数据一致性要求不那么高的场景中,通常不会使用到这套架构.

事实上,上面提到的第二点劣势也并非是 TCC 方案的缺陷,而是所有分布式事务都存在的问题,由于网络请求以及第三方系统的不稳定性,分布式事务永远无法达到 100% 的原子性.


总结

Transaction Message:能够支持狭义的分布式事务. 基于消息队列组件中半事务消息以及轮询检查机制,保证了本地事务和消息生产两个动作的原子性,但不具备事务的逆向回滚能力
TCC Transaction:能够支持广义的分布式事务. 架构中每个模块需要改造成实现 Try/Confirm/Cancel 能力的 TCC 组件,通过事务协调器进行全局 Try——Confirm/Cancel 两阶段流程的串联,保证数据的最终一致性趋近于 100%

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/151909.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

keepalived安装配置(服务器主备、负载均衡)

系统拓扑 安装keepalived 主备服务器上都需要安装 在线安装 yum install -y keepalived 离线安装 # todo 服务器准备 虚拟机ip:192.168.11.56 主服务器:192.168.11.53 备服务器:192.168.11.54 配置文件修改 keepalived安装之后&…

k8s pod常用运维命令

1. 概述 kubectl 命令是操作 Kubernetes 集群的最直接和最高效的途径,熟练掌握命令的使用能起到事半功倍的效果,整理命令有助于加深记忆,该文仅记录关于pod常用的操作运维命令。 2. 查看namespaces 查看k8s集群中目前存在的namespaces kub…

Python PyQt 程序设置图标

源码运行时图标 第一步:阿里巴巴是两图标库下载喜欢的图标 iconfont-阿里巴巴矢量图标库 第二步:转化png为ico https://www.aconvert.com/cn/icon/png-to-ico/ 256x256为大图标 默认的32x32很小(不建议用) 转化后右键点击文件链接&…

创邻科技亮相ISWC 2023,国际舞台见证知识图谱领域研究突破

近日,第22届国际语义网大会 ISWC 2023 在雅典希腊召开,通过线上线下的形式,聚集了全球的顶级研究人员、从业人员和行业专家,讨论、发展和塑造语义网和知识图谱技术的未来。创邻科技CEO张晨博士作为知识图谱行业专家受邀参会&#…

十八数藏:数字创新之美,文化传承的璀璨明星

在当代数字时代,十八数藏如同一颗璀璨之星,闪耀在文化传承的广袤天空。其数字创新之美,不仅在传统工艺中绽放,更为文化守护开辟了崭新的篇章。 十八数藏的数字创新,宛如一场艺术之舞。在传统工艺的基础上,数…

部署LCM(Latent Consistency Models)实现快速出图

LCM 的全称是 Latent Consistency Models(潜在一致性模型),由清华大学交叉信息研究院的研究者们构建。通过一些创新性的方法,LCM 只用少数的几步推理就能生成高分辨率图像,将主流文生图模型的效率提高 5-10 倍&#xf…

pd19虚拟机win系统镜像(m1/intel)

入手了Mac电脑后,由于需要用到Windows软件,又嫌安装双系统太复杂,这时候Mac就用到了安装虚拟机,目前最好用的虚拟机是Parallels Desktop,win镜像版本要根据自己的喜好选对,在此提供分别兼容M1和Intel的win1…

inner join left join 什么情况效果相同

效果不同的情况 SELECT g.name AS groupName, g.root_code AS rootCode, g.data_sort AS groupDataSort, l.* FROM wise_system_point_group g LEFT JOIN wise_system_point_list l ON g.code l.group_code WHERE g.code "drug" ORDER BY g.data_sort, l.data_s…

最新完美版积分商城系统-奇偶商城系统源码+独立代理后台+附搭建教程

源码简介: 最新完美版积分商城系统,网购商城系统源码,是更新的奇偶商城系统源码,它拥有独立代理后台,而且内附搭建教程。 1.演示环境:Linux Centos7以上版本 宝塔 2.Nginx 1.18.0 PHP7.0 Mysql5.6 3…

门禁管理超级麻烦,你方式用对了吗?

随着社会的不断进步和科技的飞速发展,安全管理成为我们日常生活和工作中至关重要的一环。在这个背景下,门禁监控系统逐渐崭露头角,成为保障各类场所安全的关键工具。 客户案例 企业办公楼 在现代企业中,保护办公场所的安全至关重…

YOLOV8部署Android Studio安卓平台NCNN

下载Android Studio,配置安卓开发环境,这个过程比较漫长。 安装cmake,注意安装的是cmake3.10版本。 根据手机安卓版本选择相应的安卓版本,我的是红米K30Pro,安卓12。 使用腾讯开源的ncnn,这是一个为手机端极…

大数据可视化Echarts基础快速入门

目录 一、什么是Ehcarts? 二、如何使用Echarts (1)引入Echarts的js文件 (2)查看文档,根据文档编写代码 一、什么是Ehcarts? 首先我们要知道什么数据可视化。什么是数据可视化?…

大数据基础设施搭建 - Linux环境

文章目录 一、阿里云服务器购买二、阿里云服务器Linux环境配置2.1.1 关闭防火墙2.1.2 配置静态内网ip2.1.3 配置SSH免密登陆(免密登陆远程机器普通用户)2.1.4 文件分发工具2.1.5 命令同步执行工具 一、阿里云服务器购买 默认安全组除linux/windows远程连…

如何避免在Flask中使用Response对象

在Flask框架中,Response对象的__bool__和__nonzero__方法被重载,以便返回一个表示HTTP响应状态是否为’OK’的布尔值。然而,这可能会导致一些预期之外的行为。 解决方案 对于上述问题,可以通过直接检查Response对象的ok属性来避…

[sqlserver]在count(*)末尾增加单位(sql语句中的类型转换函数convert())

背景:在查询登录总数后面增加“人次” 解决:使用convert()函数转换为varchar类型即可 原语句: select count(*) 登录次数 from login 更改后: select convert(varchar,count(*))人次 登陆次数 from login 关于convert()函数的…

交换机堆叠 配置(H3C)堆叠中一台故障如何替换

交换机堆叠 配置(H3C)堆叠中一台故障如何替换 堆叠用来干什么?配置两台成员设备的 IRF(堆叠)Switch01配置Switch02配置 如何替换堆叠中坏掉的一台交换机 堆叠用来干什么? 一台交换机网口有限,无…

机器视觉兄弟们,职场要不要王自如,如果你打工了,你就是被“包养”,就不要谈什么独立人格!

打工是什么意思? 从字面来看,词语中的“打”,意思是从事,进行:“”指工作。所以打工就是从事工作。那为什么不叫上班呢?打工多指农村人背井离乡到经济发达地方去工作。打工者经受了身心的艰难困苦&#xf…

nginx基本配置-基于nuc980开发板的笔记

一、介绍 前面的文章<nginx交叉编译移植-基于nuc980开发板的笔记>,介绍了如何移植nginx到开发板&#xff0c;打开的网页面是默认的网页。下面介绍如何输入网址变为指定的网页。 二、配置 ①将编写的网页&#xff0c;放到html文件夹下&#xff0c;如下图&#xff1a; ②打…

小红书x-s、x-s-common算法研究与分析(仅供学习)

文章目录 1. 写在前面2. 参数分析2.1. x-s、x-t、x-s-common 1. 写在前面 最近花时间分析了一下xhs&#xff0c;研究的不深&#xff0c;也参考了网上许多开源出来的案例。简单记录一下&#xff0c;感兴趣的将就看一下吧&#xff01; 之前也研究过一段时间的某音&#xff0c;下…

Redis分布式锁(中)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 我们在不久前介绍了Spr…
最新文章