分布式事务方案分析:两阶段和TCC方案(图+文)

news/2025/1/2 1:35:41/

1 缘起

补充事务相关知识过程中,
发现,默认的知识都是基于单体服务的事务,比如ACID,
然而,在一些复杂的业务系统中,采用微服务架构构建各自的业务,
就有了分布式事务的概念,比如,一致性在单体服务和分布式服务中的场景是有一定差别的,
但是,都是为了尽最大努力保证:原子性、一致性、持久化,
单体服务中事务的一致性是强一致性,而分布式服务的事务一致性会分为:强一致性、弱一致性和最终一致性,
因此,有必要学习下分布式事务相关的知识,
分享如下,帮助轻松应对知识交流和考核。

单体服务事务相关文章:
https://blog.csdn.net/Xin_101/article/details/102246522
https://blog.csdn.net/Xin_101/article/details/102240949

2 分布式事务

2.1 为什么

为什么会有分布式事务?
既是业务问题,又是技术问题。随着业务的多元化与复杂度的增加,在技术实现层面进行了合理的业务划分,当完成业务划分后,本应该在一个会话或命令空间中的操作,散落到各个服务中,于是,有了分布式事务相关的问题。
有人会想,这不是自己给自己挖坑吗?为什么要把服务分开,都在一起不就好了?其实,对于技术实现而言,只有相对合理,没有绝对边界,在这里挖坑的土,可能是填另外一个坑的原料,虽然业务拆分有分布式等相关问题,但是,也解决了一部分其他问题,比如服务耦合、服务庞大一荣俱荣,一损俱损等(微服务带来的优势)。
关于为什么有分布式事务这个问题以及方案,不同的业务会有不同见解,不是所有业务都要考虑分布式相关的问题,因地制宜即可,我们在学习或研究某些方案的过程中,不见得会立马用到,而是为了填充我们的知识库,当遇到问题时,多一些思路,多一些方案,最终解决问题。

2.2 方案

分布式事务方案可分为两类。
(1)基于事务的分布式事务方案;
(2)基于业务的分布式事务方案。
其中,
(1)基于事务的分布式事务是将各个事务串联,并添加首先各个服务开启各自事务,然后执行CURD,将执行结果上报至统一事务管理器,统一事务管理器汇总各个事务结果,然后向各个事务发布提交或回滚的指令。
(2)基于业务的分布式事务在各自服务中维护完整的事务生命周期,与其他相关联的事务进行隔离,同时维护中间状态的数据,各个服务将各自的事务执行结果上报至统一事务管理器,统一事务管理器汇总各个事务结果,然后向各个服务发布提交或回滚的指令。
根据上述直到思想,出现了两种实际的方案:
两阶段提交和TCC。

2.1 两阶段提交(2PC,Two-phrase commit)

两阶段提交就是基于事务的分布式事务解决方案。
将分布式事务分成两个执行阶段:
(1)一阶段开启事务,执行操作;
(2)二阶段提交或回滚事务;
由统一事务管理器控制事务的执行。

2.1.1 一阶段

一阶段各个服务开启事务并执行相关的操作,将执行结果汇报给统一事务管理器,各个服务不会自动提交事务,只是上报执行结果。
一阶段执行示意图如下图所示,由图可知,
统一事务管理器接收到用户请求后,向各个本地事务管理器发送开启事务并执行CURD的指令,
在第一阶段,各个事务完成了除了提交的所有操作。

在这里插入图片描述

2.1.2 二阶段

二阶段统一事务管理器将各个服务事务的执行结果汇总,最终决定向各个事务发布提交或者回滚的指令;
(1)提交:全部服务事务执行结果均成功;
(2)回滚:任意一个服务事务出现失败;

提交

二阶段提交示意图如下图所示,由图可知,本地事务管理器将执行状态上报给统一事务管理器,
统一事务管理器综合处理后,给各个本地事务管理器发送指令,
当本地事务管理器的执行结果均成功时,统一事务管理器向各个本地事务管理器发送提交指令,
完成事务提交。
在这里插入图片描述

回滚

当任意一个本地事务管理器执行失败时,
统一事务管理器会向各个本地事务管理器发送回滚指令,
事务回滚。
在这里插入图片描述

2.1.3 存在的问题

(1)同步阻塞:当参与的事务使用公共资源时,其他事务参与者只能阻塞等待;
(2)单点故障:统一事务管理器出现故障时,整个系统不可用;
(3)数据不一致:二阶段,如果统一事务管理器只发送了提交指令,刚好网络异常,只有部分本地事务管理器接收到提交指令,另外一部分无法提交事务,数据不一致;
(4)不确定性:统一事务管理器发送提交指令后,部分本地事务管理器收到提交指令,刚好统一事务管理器和接收到提交指令的事务宕机,重新选举的统一事务管理器无法确定该消息是否提交成功。

2.2 TCC方案(Try-Confirm-Cancel)

TCC是基于业务的分布式事务方案。将完整的事务分成三个业务阶段独立维护执行:
Try-Confirm-Cancel。
其中,
Try:独立维护事务,原始数据CURD,同时操作预留数据,为后续提交或回滚做准备;
Confirm:独立维护事务,预留数据CURD,完成提交;
Cancel:独立维护事务,原始数据CURD,同时操作预留数据,完成回滚;
同样,需要一个统一事务管理器,基于业务的协调者,向各个独立的事务发布操作指令。
执行过程:
(1)提交:各个服务进入Try阶段,Try阶段全部执行成功,进入Confirm阶段,Confirm阶段全部执行成功:提交;
(2)回滚:各个服务进入Try阶段,Try阶段任意一个事务失败,进入Cancel阶段:回滚;
(3)回滚:各个服务进入Try阶段,Try阶段全部执行成功,进入Confirm阶段,Confirm阶段任意一个事务失败:回滚。

2.2.1 提交

TCC提交示意图如下图所示,由图可知,
基于业务的分布式事务,在各个服务中的各个阶段(Try,Confirm和Cancel),
维护自己的事务,执行完成后,将执行结果上报至统一事务管理器,
然后由统一事务管理器分发下一个阶段的指令。
(1)用户请求后,统一事务管理器将执行消息分发到各个服务,各个服务进入Try阶段,将Try阶段执行结果上报至统一事务管理器;
(2)统一事务管理器收集到Try阶段执行结果后,所有结果均是成功的,统一事务管理器向各个服务发送进入Confirm的指令,开始执行Confirm阶段的任务,各个服务将执行结果上报至统一事务管理器;
(3)统一事务管理器收集到Confirm阶段执行结果后,所有结果均是成功的,完成提交。

在这里插入图片描述

2.2.2 回滚

回滚则有两种情况:
(1)Try阶段异常:回滚;
(2)Confirm阶段异常:回滚;

Try阶段回滚

Try阶段回滚示意图如下图所示,由图可知,
(1)用户请求后,统一事务管理器将执行消息分发到各个服务,各个服务进入Try阶段,将Try阶段执行结果上报至统一事务管理器;
(2)统一事务管理器收集到Try阶段执行结果后,发现有Try异常,有Try正常,统一事务管理器向各个服务发送进入Cancel的指令,开始执行Cancel阶段的任务,完成回滚。
在这里插入图片描述

Confirm阶段回滚

Confirm阶段回滚示意图如下图所示,由图可知,
(1)用户请求后,统一事务管理器将执行消息分发到各个服务,各个服务进入Try阶段,将Try阶段执行结果上报至统一事务管理器;
(2)统一事务管理器收集到Try阶段执行结果后,所有结果均是成功的,统一事务管理器向各个服务发送进入Confirm的指令,开始执行Confirm阶段的任务,各个服务将执行结果上报至统一事务管理器;
(3)统一事务管理器收集到Confirm阶段执行结果后,有Confirm异常,有的Confirm正常,统一事务管理器向各个服务发送进入Cancel的指令,开始执行Cancel阶段的任务,完成回滚。
在这里插入图片描述

3 小结

(1)两阶段分布式事务方案基于事务(数据库层面)的分布式方案,TCC分布式事务方案基于业务的分布式方案;
(2)两阶段提交是强一致方案,但是仍有数据不一致的情况,统一事务管理器存在单点故障问题,导致整个系统不可用;
(3)TCC是基于业务的方案,在业务层面,业务侵入性大,实现复杂;
(4)提交:所有阶段均成功;回滚:任意阶段出现异常、失败等。


【参考文献】
[1]https://xiaomi-info.github.io/2020/01/02/distributed-transaction/
[2]https://zhuanlan.zhihu.com/p/183753774?utm_source=wechat_session
[3]https://blog.csdn.net/qq_45066628/article/details/119192658


http://www.ppmy.cn/news/10635.html

相关文章

vue3中的写法以及,一些语法糖

vue3新增setup,属性执行比 created更早,同时setup中this不会指向实例)这个方法在onBeforeMounted之前被调用。定义数据需要在数据前面加ref,ref在vue3中是将数据转换成响应式数据结构的一种,因为vue3中没有了data(){ },那么就没办法劫持数据做…

TypeScript学习(四)函数

文章目录1.定义函数2.函数类型3.可选类型和默认参数4.剩余参数5.this1.定义函数 使用function关键字来定一个函数。 function hello() {console.log("hello") }hello(); // hello2.函数类型 和变量一样,在TypeScript中,函数同样可以像变量一样…

宝塔Linux面板安装MySQL数据库,并且开启远程链接

1.宝塔面板【软件商店】->【应用搜索】,搜索MySQL,然后点击安装想要的版本,我这边是安装的5.6版 2. 安装完后重置数据库管理员密码 3.Navicat Premium 15连接数据库 4.外网navicat工具无法连接数据库的处理办法 4.1输入 mysql -u root -p 后回车&a…

我与CSDN2022年的故事

目录 人生之中,初识博客 踏上csdn博客之路 审核成后的10分钟 第一条博客成功发布 得到恩师的鼓励 发布后的二十分钟 星星之火,可以燎原 每时每刻,都在博客 开发热爱,愈发癫狂 传播之路,渐渐开始 泥泞路上&a…

9.Isaac教程-- Laikago 四足机器人的自主导航

Laikago 四足机器人的自主导航 开发智能机器人系统是一项多学科的工作,集成了动力学、控制、计算机视觉、人工智能等。 很难掌握所有这些领域。 即使你掌握了所有这些,也需要花费大量时间才能正确和稳健。 为了帮助机器人专家加速智能机器人的开发&…

架构设计---用户加密处理

前言: 在互联网各种安全问题中,最能引发话题,刺激大众神经的就是用户的泄密问题,数据库被拖库导致所有的数据泄露,这种系统安全问题涉及的因素可能有很多,大部分和开发软件的程序员没有关系,但…

SOA 和微服务有何区别?

玩过 Dubbo 的小伙伴应该都有听说过一个概念叫做 SOA,每当我们说起微服务的时候,很多人就会去纠结这和 SOA 有啥关系呀?感觉换汤不换药呀。 今天松哥来稍微和小伙伴们讨论下这个话题,我们一起来看看 SOA 和微服务到底有何异同。 …

【数据结构趣味多】循环队列

目录 函数介绍及模拟实现 Front()函数 Rear()函数 enQueue()函数 deQueue()函数 isEmpty()函数 isFull()函数 循环队列模拟题 定义:把队列的头尾相连接的的顺序存储结构称为循环队列;循环队列的是由顺序表实现的。 为什么要使用循环队列&#…