写点什么

分布式事务

作者:想要飞的猪
  • 2022 年 9 月 13 日
    广东
  • 本文字数:2143 字

    阅读完需:约 7 分钟

两端提交方案/XA 方案


  2PC(Two-phase commit protocol),称为二阶段提交。二阶段提交是一种强一致性设计。2PC引入一个事务协调者的角色来协调管理各个事务参与者(也可以称为本地资源)的提交与回滚,二阶段分别指的是准备阶段,提交阶段。
复制代码


准备阶段


 协调者给每个参与者发送准备命令,每个参与者收到命令后准备事务的相关事宜,准备好后(相当于数据库中执行了脚本但是还没有提交)给协调者发送准备好可以提交后,协调者收到所有的参与者的消息,根据每个参与者的消息做出提交或者是回滚的决定。
复制代码


提交或者是回滚


第二阶段有两中情况:1、回滚 协调者判断出回滚时,发送回滚命令,不断的重试,知道所有的参与者都回滚,不然在第一阶段参与者会一直阻塞。
复制代码


2、执行提交命令,也是不断的重试直到所有的参与者都提交完成,最后不行时只能人工介入。


问题


2PC 是一种尽量保证强一致的分布式事务,因此他是同步阻塞的,而同步阻塞就会有资源长久锁定的风险,总体而言效率较低并且存在单点故障,极端情况下存在数据不一致的风险;还有一点2PC只适用于支持事务的数据库层面的事务场景,而平时我们使用的不支持事务的数据库,以及一些其他操作如上传图片,发送短信等等。
复制代码


3PC


3PC的出现是为了解决2PC中出现的一些问题,相比于2PC,3PC在参与者中引入了超时机制,并且新增了一个阶段使参与者可以利用这一个阶段统一各自的状态。
3PC包含了三个阶段,分别是准备阶段,预提交阶段和提交阶段
复制代码


准备阶段:协调者询问各个参与者的情况,比如资源是否够了,是否能够完成事务操作等等;


预提交阶段:和 2pc 中的准备阶段一样,把除了提交事务以外的其他事情都做完;


提交阶段:与 2PC 一样,提交事务。


3PC 的引入是为了解决提交阶段 2PC 协调者和某参与者都挂了之后新选举的协调者不知道当前应该是提交还是回滚的问题,但是也只是让协调者知道如何做,并不能确认参与者是否已经执行了命令。


2PC 与 3PC 都不能保证数据的 100%一致,因此一般都需要有定时扫描补偿机制。


协调者故障导致的问题


1、协调者在发送第一阶段前挂了,事务还没有开始


2、协调者在发送第一阶段命令后挂了,那所有参与者都将阻塞,


3、发送回滚命令之前挂了,事务也执行不下去,且参与者都将阻塞;


4、发送回滚命令之后挂了,有可能会有部分参与者因为网络原因等没有回滚,阻塞着;


5、发送提交命令之前挂了,所有参与者阻塞


6、发送提交命令之后挂了,也有可能会有部分参与者收不到命令而阻塞;


TCC


TCC是业务层面实现的分布式事务,它不仅仅适用支持事务的数据库层面,还只是其他的操作,如发送消息,发送短线,上传文件等等。
复制代码


TCC 指的是 try-confim-cancel 三个阶段


  • try 指的是预留,即资源的预留和锁定。

  • Confirm 指的是确认操作,这一步其实就是真正执行了

  • Cancel 指的是撤销操作,可以理解为把预留阶段的动作撤销了


TCC 适用范围大,但开发量也更大,都需要在业务上实现,所以 TCC 可以跨数据库实现事务。


TCC 存在问题:


1、业务入侵,需要在业务代码层面完成;
2、实现难度较大,对开发者要求较高
3、空回滚
空回滚就是对于一个分布式事务,在没有调用TCC资源try方法的情况下,调用了二阶段的Cancel方法,解决方案:Cancel方法需要识别出是空回滚然后直接返回成功。
造成空回滚的情况:先向TC注册一个分支事务,然后去执行RPC框架调用逻辑,这时候调用方宕机,网络异常都会导致RPC调用失败,未执行Try方法,但是分布式事务已经开启了,需要完成到最终态,因此会调用Cancel接口,导致形成了空回滚。
解决方法:另外增加一个事务记录表,主要有事务ID ,分支事务ID,事务执行情况等等,在事务try阶段会插入一条记录,表示执行了try,所以在Cancel时检查一下是否执行了,没有则是空回滚,直接返回成功。
4、幂等
幂等就是对于同一个事务的同一个分支事务,重复的调用该分支事务的第二阶段接口,因此要求TCC的二阶段Confirm与Cancel接口保证幂等性,不会重复适用或者释放资源。没有控制好幂等,则可能导致资源损失等问题。
复制代码


解决方案:在解决空回滚的事务控制表中记录事务的状态


5、悬挂
悬挂就是指的是,事务已经完成了,有一些参与者才执行try方法,因为事务已经完成了,所以没有后续处理这个预留的资源了;导致的原因就是网络拥堵,导致 了空回滚的情况,因为已经执行了Cancel了,所以事务结束了,这时执行try方法的指令才到RM(参与者);
复制代码


解决方案:与空回滚、幂等一样,在执行 try 方法时检查一下事务控制表中的事务执行状态,是否已经执行过了第二阶段了,如果执行过了则直接返回成功,不执行 try 方法。


本地消息表


本地消息表是最终一致性,在A系统本地的事务中首先写业务表,然后再写消息表,然后再将消息发送到MQ中,再B系统中需要先将消息写入表,这是为了保证消息重复消费,为了保证消息幂等性,我们可以使用数据库唯一键约束。
再B系统完成后需要通知A系统已经完成,A更新成功后,开始发送下一条消息;A系统中要有一个后台线程不断的去判断A系统的状态为待确认的消息,设置超时机制,如果超时则重新发送到MQ中,直到执行成功,达到一定条件要人工干预。
因为是要写入消息表,再搞定发的情况下会有大量的IO ,因此不适用高并发场景。
复制代码


可靠消息最终一致性方案


 该方案与本地消息表方案相似,只是把本地消息表改为使用MQ代替,如阿里的RocketMQ就只是消息事务。
复制代码


用户头像

还未添加个人签名 2020.06.05 加入

还未添加个人简介

评论

发布
暂无评论
分布式事务_3PC_想要飞的猪_InfoQ写作社区