为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

单机版事务都不会严格遵守事务的严格实现,更别说分布式事务了,所以在现实情况下我们只能实现残缺版的事务。

在明确了事务和分布式事务之后,我们就先来看看常见的分布式事务方案:2PC、3PC、TCC、本地消息、事务消息。

2PC

===

2PC,Two-phase commit protocol,即两阶段提交协议。它引入了一个事务协调者角色,来管理各个参与者(就是各数据库资源)。

整体分为两个阶段,分别是准备阶段和提交/回滚阶段。

我们先来看看第一个阶段,即准备阶段。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

由事务协调者给每个参与者发送准备命令,每个参与者收到命令之后会执行相关事务操作,你可以认为除了事务的提交啥都做了。

然后每个参与者会返回响应告知协调者自己是否准备成功。

协调者收到每个参与者的响应之后就进入第二阶段,根据收集的响应,如果有一个参与者响应准备失败那么就向所有参与者发送回滚命令,反之发送提交命令。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

这个协议其实很符合正常的思维,就像我们大学上课点名的时候,其实老师就是协调者的角色,我们都是参与者。

老师一个一个的点名,我们一个一个的喊到,最后老师收到所有同学的到之后就开始了今天的讲课。

而和点名有所不同的是,老师发现某几个学生不在还是能继续上课,而我们的事务可不允许这样。

事务协调者在第一阶段未收到个别参与者的响应,则等待一定时间就会认为事务失败,会发送回滚命令,所以在 2PC 中事务协调者有超时机制。

我们再来分析一下 2PC 的优缺点。

2PC 的优点是能利用数据库自身的功能进行本地事务的提交和回滚,也就是说提交和回滚实际操作不需要我们实现,不侵入业务逻辑由数据库完成,在之后讲解 TCC 之后相信大家对这点会有所体会。

2PC 主要有三大缺点:同步阻塞、单点故障和数据不一致问题。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

同步阻塞

====

可以看到在第一阶段执行了准备命令后,我们每个本地资源都处于锁定状态,因为除了事务的提交之外啥都做了。

所以这时候如果本地的其他请求要访问同一个资源,比如要修改商品表 id 等于 100 的那条数据,那么此时是被阻塞住的,必须等待前面事务的完结,收到提交/回滚命令执行完释放资源后,这个请求才能得以继续。

所以假设这个分布式事务涉及到很多参与者,然后有些参与者处理又特别复杂,特别慢,那么那些处理快的节点也得等着,所以说效率有点低。

单点故障

====

可以看到这个单点就是协调者,如果协调者挂了整个事务就执行不下去了。

如果协调者在发送准备命令前挂了还行,毕竟每个资源都还未执行命令,那么资源是没被锁定的。

可怕的是在发送完准备命令之后挂了,这时候每个本地资源都执行完处于锁定状态了,都杵着了,这就很僵硬了,如果是某个热点资源都阻塞了,这估计就要GG了。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

数据不一致问题

=======

因为协调者和参与者之间的交流是经过网络的,而网络有时候就会抽风的或者发生局部网络异常。

那么就有可能导致某些参与者无法收到协调者的请求,而某些收到了。比如是提交请求,然后那些收到命令的参与者就提交事务了,此时就产生了数据不一致的问题。

小结一下 2PC

========

至此我们来先小结一些 2PC ,它是一个同步阻塞的强一致性两阶段提交协议,分别是准备阶段和提交/回滚阶段。

2PC 的优势在于对业务没有侵入,可以利用数据库自身机制来进行事务的提交和回滚。

它的缺点:是一个同步阻塞协议,会导致高延迟和性能的下降,并且存在协调者单点故障问题,极端情况下会有数据不一致的问题。

当然这只是协议,具体的落地还是可以变通了,比如协调者单点问题,我就搞个主从来实现协调者,对吧。

分布式数据库的 2PC 改进模型

================

可能有些人对分布式数据库不熟悉,没有关系,我们主要学的是思想,看看人家的思路。

我简单的讲下 Percolator 模型,它是基于分布式存储系统 BigTable 建立的模型,BigTable 是啥也不清楚的同学没有关系影响不大。

还是拿转账的例子来说,我现在有 200 块钱,你现在有 100 块钱,为了突出重点我也不按正常的结构来画这个表。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

然后我要转 100 块给你。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

此时事务管理器发起了准备请求,然后我账上的钱就少了,你账上的钱就多了,而且事务管理器还记录下这次操作的日志。

此时的数据还是私有版本,别的事务是否不到的,简单的理解 Lock 上有值就还是私有的。

可以看到我的记录 Lock 标记的是 PK,你的记录标记的是指向我的记录指针,这个 PK 是随机选择的。

然后事务管理器会向被选择作为 PK 的那条记录发起提交指令。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

此时就会把我的记录的锁给抹去了,这等于我的记录不再是私有版本了,别的事务就都能访问了。

那你的记录上还有锁啊?不用更新吗?

嘿嘿不需要及时更新,因为访问你的这条记录的时候会去根据指针找我的那个记录,发现记录已经提交了所以你的记录就可以被访问了。

有人说这效率不就差了,每次都要去找一次,别急。

后台会有个线程来扫描,然后更新把锁记录给去了。

这不就稳了嘛。

相比于 2PC 的改进

===========

首先 Percolator 在提交阶段不需要和所有的参与者交互,主需要和一个参与者打交道,所以这个提交是原子的!解决了数据不一致问题。

然后事务管理器会记录操作日志,这样当事务管理器挂了之后选举的新事务管理器就可以通过日志来得知当前的情况从而继续工作,解决了单点故障问题。

并且 Percolator 还会有后台线程,会扫描事务状况,在事务管理器宕机之后会回滚各个参与者上的事务。

可以看到相对于 2PC 还是做了很多改进的,也是巧妙的。

其实分布式数据库还有别的事务模型,不过我也不太熟悉,就不多哔哔了,有兴趣的同学可以自行了解。

还是挺能拓宽思想的。

XA 规范

=====

让我们再回来 2PC,既然说到 2PC 了那么也简单的提一下 XA 规范,XA 规范是基于两阶段提交的,它实现了两阶段提交协议。

再说 XA 规范之前又得先提一下 DTP 模型,即 Distributed Transaction Processing,这模型规范了分布式事务的模型设计。

而 XA 规范又约束了 DTP 模型中的事务管理器(TM) 和资源管理器(RM)之间的交互,简单的说就是你们两之间要按照一定的格式规范来交流!

我们先来看下 XA 约束下的 DTP 模型。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

  • AP 应用程序,就是我们的应用,事务的发起者。

  • RM 资源管理器,简单的认为就是数据库,具备事务提交和回滚能力,对应我们上面的 2PC 就是参与者。

  • TM 事务管理器,就是协调者了,和每个 RM 通信。

简单的说就是 AP 通过 TM 来定义事务操作,TM 和 RM 之间会通过 XA 规范进行通信,执行两阶段提交,而 AP 的资源是从 RM 拿的。

从模型上看有三个角色,而实际实现可以由一个角色实现两个功能,比如 AP 来实现 TM 的功能,TM 没必要抽出来单独部署。

MySQL XA

========

知晓了 DTP 之后,我们就来看看 XA 在 MySQL 中是如何操作的,不过只有 InnoDB 支持。

简单的说就是要先定义一个全局唯一的 XID,然后告知每个事务分支要进行的操作。

可以看到图中执行了两个操作,分别是改名字和插入日志,等于先注册下要做的事情,通过 XA START XID 和 XA END XID 来包裹要执行的 SQL。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

然后需要发送准备命令,来执行第一阶段,也就是除了事务的提交啥都干了的阶段。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

然后根据准备的情况来选择执行提交事务命令还是回滚事务命令。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

基本上就是这么个流程,不过 MySQL XA 的性能不高这点是需要注意的。

可以看到虽说 2PC 有缺点,但是还是有基于 2PC 的落地实现的,而 3PC 的引出是为了解决 2PC 的一些缺点,但是它整体下来开销更大,也解决不了网络分区的问题,我也没有找到 3PC 的落地实现。

不过我还是稍微提一下,知晓一下就行,纯理论。

3PC

===

3PC 的引入是为了解决 2PC 同步阻塞和减少数据不一致的情况。

3PC 也就是多了一个阶段,一个询问的阶段,分别是准备、预提交和提交这三个阶段。

准备阶段单纯就是协调者去访问参与者,类似于你还好吗?能接请求不。

预提交其实就是 2PC 的准备阶段,除了事务的提交啥都干了。

提交阶段和 2PC 的提交一致。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

3PC 多了一个阶段其实就是在执行事务之前来确认参与者是否正常,防止个别参与者不正常的情况下,其他参与者都执行了事务,锁定资源。

出发点是好的,但是绝大部分情况下肯定是正常的,所以每次都多了一个交互阶段就很不划算。

然后 3PC 在参与者处也引入了超时机制,这样在协调者挂了的情况下,如果已经到了提交阶段了,参与者等半天没收到协调者的情况的话就会自动提交事务。

不过万一协调者发的是回滚命令呢?你看这就出错了,数据不一致了。

还有维基百科上说 2PC 参与者准备阶段之后,如果协调者挂了,参与者是无法得知整体的情况的,因为大局是协调者掌控的,所以参与者相互之间的状况他们不清楚。

而 3PC 经过了第一阶段的确认,即使协调者挂了参与者也知道自己所处预提交阶段是因为已经得到准备阶段所有参与者的认可了。

简单的说就像加了个围栏,使得各参与者的状态得以统一。

小结 2PC 和 3PC

============

从上面已经知晓了 2PC 是一个强一致性的同步阻塞协议,性能已经是比较差的了。

而 3PC 的出发点是为了解决 2PC 的缺点,但是多了一个阶段就多了一次通讯的开销,而且是绝大部分情况下无用的通讯。

虽说引入参与者超时来解决协调者挂了的阻塞问题,但是数据还是会不一致。

可以看到 3PC 的引入并没什么实际突破,而且性能更差了,所以实际只有 2PC 的落地实现。

再提一下,2PC 还是 3PC 都是协议,可以认为是一种指导思想,和真正的落地还是有差别的。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

TCC

===

不知道大家注意到没,不管是 2PC 还是 3PC 都是依赖于数据库的事务提交和回滚。

而有时候一些业务它不仅仅涉及到数据库,可能是发送一条短信,也可能是上传一张图片。

所以说事务的提交和回滚就得提升到业务层面而不是数据库层面了,而 TCC 就是一种业务层面或者是应用层的两阶段提交。

TCC 分为指代 Try、Confirm、Cancel ,也就是业务层面需要写对应的三个方法,主要用于跨数据库、跨服务的业务操作的数据一致性问题。

TCC 分为两个阶段,第一阶段是资源检查预留阶段即 Try,第二阶段是提交或回滚,如果是提交的话就是执行真正的业务操作,如果是回滚则是执行预留资源的取消,恢复初始状态。

比如有一个扣款服务,我需要写 Try 方法,用来冻结扣款资金,还需要一个 Confirm 方法来执行真正的扣款,最后还需要提供 Cancel 来进行冻结操作的回滚,对应的一个事务的所有服务都需要提供这三个方法。

可以看到本来就一个方法,现在需要膨胀成三个方法,所以说 TCC 对业务有很大的侵入,像如果没有冻结的那个字段,还需要改变结构。

我们来看下流程。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

虽说对业务有侵入,但是 TCC 没有资源的阻塞,每一个方法都是直接提交事务的,如果出错是通过业务层面的 Cancel 来进行补偿,所以也称补偿性事务方法。

这里有人说那要是所有人 Try 都成功了,都执行 Comfirm 了,但是个别 Confirm 失败了怎么办?

这时候只能是不停地重试调失败了的 Confirm 直到成功为止,如果真的不行只能记录下来,到时候人工介入了。

TCC 的注意点

========

这几个点很关键,在实现的时候一定得注意了。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

幂等问题,因为网络调用无法保证请求一定能到达,所以都会有重调机制,因此对于 Try、Confirm、Cancel 三个方法都需要幂等实现,避免重复执行产生错误。

空回滚问题,指的是 Try 方法由于网络问题没收到超时了,此时事务管理器就会发出 Cancel 命令,那么需要支持 Cancel 在未执行 Try 的情况下能正常的 Cancel。

悬挂问题,这个问题也是指 Try 方法由于网络阻塞超时触发了事务管理器发出了 Cancel 命令,但是执行了 Cancel 命令之后 Try 请求到了,你说气不气。

这都 Cancel 等你来个 Try,对于事务管理器来说这时候事务已经是结束了的,这冻结操作就被“悬挂”了,所以空回滚之后还得记录一下,防止 Try 的再调用。

TCC 变体

======

上面我们说的是通用型的 TCC,它需要改造以前的实现,但是有一种情况是无法改造的,就是你调用的是别的公司的接口。

没有 Try 的 TCC

============

比如坐飞机需要换乘,换乘的又是不同的航空公司,比如从 A 飞刀 B,再从 B 飞刀 C,只有 A - B 和 B - C 都买到票了才有意义。

这时候的选择就没得 Try 了,直接调用航空公司的买票操作,当两个航空公司都买成功了那就直接成功了,如果某个公司买失败了,那就需要调用取消订票接口。

也就是在第一阶段直接就执行完整个业务操作了,所以要重点关注回滚操作,如果回滚失败得有提醒,要人工介入等。

这其实就是 TCC 的思想。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

异步 TCC

======

这 TCC 还能异步?其实也是一种折中,比如某些服务很难改造,并且它又不会影响主业务决策,也就是它不那么重要,不需要及时的执行。

这时候可以引入可靠消息服务,通过消息服务来替代个别服务来进行 Try、Confirm、Cancel 。

Try 的时候只是写入消息,消息还不能被消费,Confirm 就是真正发消息的操作,Cancel 就是取消消息的发送。

这可靠消息服务其实就类似于等下要提到的事务消息,这个方案等于糅合了事务消息和 TCC。

TCC 小结

======

可以看到 TCC 是通过业务代码来实现事务的提交和回滚,对业务的侵入较大,它是业务层面的两阶段提交,。

它的性能比 2PC 要高,因为不会有资源的阻塞,并且适用范围也大于 2PC,在实现上要注意上面提到的几个注意点。

它是业界比较常用的分布式事务实现方式,而且从变体也可以得知,还是得看业务变通的,不是说你要用 TCC 一定就得死板的让所有的服务都改造成那三个方法。

本地消息表

=====

本地消息就是利用了本地事务,会在数据库中存放一直本地事务消息表,在进行本地事务操作中加入了本地消息的插入,即将业务的执行和将消息放入消息表中的操作放在同一个事务中提交

这样本地事务执行成功的话,消息肯定也插入成功,然后再调用其他服务,如果调用成功就修改这条本地消息的状态。

如果失败也不要紧,会有一个后台线程扫描,发现这些状态的消息,会一直调用相应的服务,一般会设置重试的次数,如果一直不行则特殊记录,待人工介入处理。

可以看到还是很简单的,也是一种最大努力通知思想。

为了弄懂分布式“花了整整三天”,我把分布式事务搞完了

事务消息

====

这个其实我写过一篇文章,专门讲事务消息,从源码层面剖析了 RocketMQ 、Kafka 的事务消息实现,以及两者之间的区别。

在这里我不再详细阐述,因为之前的文章写的很详细了,大概四五千字吧。我就附上链接了:事务消息

Seata 的实现

=========

首先什么是 Seata ,摘抄官网的一段话。

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

可以看到提供了很多模式,我们先来看看 AT 模式。

AT模式

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

写在最后

还有一份JAVA核心知识点整理(PDF):JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算…

[外链图片转存中…(img-8wBHvtyQ-1713448086396)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值