1、2PC 模式

2PC 就是我们说的二阶段提交,又叫做 XA Transactions。

MySQL 从 5.5 版本开始支持,SQL Server 2005 开始支持,Oracle 7 开始支持。

这个二阶提交协议呢,就是把我们整个分布式事务拆成了两个阶段。

image.png

假设我们这有一个本地资源管理器,一个事务管理器

本地资源管理器是每一个服务的事务管理器

比如我们有一个订单服务,还有一个库存服务,那现在这是两个服务,这两个服务呢想要做一个分布式事务,两个一起成或者一起败。

接下来得有一个总的事务管理器

总的事务管理器让我们的分布式事务分为两个阶段,

首先我们总事务管理器会询问每一个微服务里的的小事务管理器,都准备好了没有?

然后,这些小事务管理器会检查它们当前的这些数据有没有准备好、连接正不正常、能不能提交数据?

如果一切都准备好,就差提交了。就会告诉我们的总事务管理器,它们都准备好了

接下来总事务管理器只要收到两个小事务都说准备好了,总事务管理器就叫这两个人发命令让 它们提交。这两个服务就会纷纷提交,然后就成功了

但是如果在询问阶段,有一个小事务说自己不能提交,那事务管理器知道之后,就会要求所有人回滚

这就是是我们说的这个二阶提交协议

  1. 准没准备好数据、能不能提交、连接正不正常
  2. 提交

优点

比较简单,而且数据库是原生支持的,特别是我们商业数据库,它的支持度也非常好。
所以我们使用它的话呢,基本上少量配置就直接能用了,遵循规范标准就行。

缺点

性能不理想,特别不适用于大型互联网场景高并发的情况下。

这种情况下,我们这个 XA 根本就没法工作了,因为它要占用大量的锁定资源。

然后它还有各种不理想的情况。

  • 许多 nosql 也没有支持 XA,这让 XA 的应用场景变得非常狭隘。
  • 也有 3PC,引入了超时机制(无论协调者还是参与者,在向对方发送请求后,若长时间未收到回应,则做出相应处理)

总结

了解即可,使用非常少

3PC 模式

也可以了解一下三阶提交协议,了解即可

三阶提交其实将整个预备又化成了两个阶段。

  1. 能否提交
  2. 能否准备好数据
  3. 提交

先问大家,你们这些数据能否提交,然后大家回答能提交,

它就让大家来准备这些数据,我们来开始提交。然后大家就准备这些数据来提交。

然后最后一个阶段,只要大家都告诉 它准备好了, 它就让所有人都去提交。

2、柔性事务 - TCC 事务补偿方案

这二阶提交协议呢,它看起来就像刚性事务。

就像是,我命令你们都提交,那你们都能提交,只要命令过去了,这个状态呢就是一致的。

但是在分布式里边,更多使用的是柔性事务

什么叫柔性事务?

刚性事务就是我们说的遵循 ACID 这个原则的事务,强一致性的。

柔性事务就是遵循我们之前说的 BASE 理论,实现最终一致性的。

TCC 事务补偿方案是怎么工作的?

image.png

比如呢我们现在有两个服务,两个服务要操作两个数据库。比如订单服务、库存服务。

TCC 模式就是我们开发人员在写每个业务代码的时候,还要写出对应的回调方法,准备让别人回调。

分别是这三个阶段

第一个是 Try,尝试阶段,就是我们预准备一些数据。

接下来第二阶段就是 Confirm,就是把我们准备的数据提交。

第三个阶段呢就是 Cancel,想要回滚我们提交的数据。

image.png

比如我们之前给 它加二了,那我们的 Cancel 这一行业务代码写的逻辑就应该是减二。

当然这三块代码都得我们开发人员自己编写,

编写以后呢,就相当于订单服务、库存服务我们都有这三行代码,

订单呢有它的 Try 逻辑,Confirm 逻辑和 Cancel 逻辑。

库存也有 Try、Confirm、Cancel 逻辑。

接下来我们的这个主服务、业务活动管理器,就先来执行第一阶段。

第一阶段,先命令大家去来预准备自己的数据。

那订单服务和我们的库存服务都会调用各自编写的 Try 模块的这些方法。

比如实现了一个接口,这个接口里边有一个叫tryLockStock(),尝试锁定这个库存。所以大家都先来执行 Try,

都执行成功,进入第二阶段,大家都来提交。

Confirm 就是将我们 Try 准备的这些数据提交,订单一提交,库存也一提交。

接下来就是关键第三阶段了。只要有任何一个服务失败,订单失败或者库存失败,或者调用订单、库存的这个大业务在最后失败了。

接下来我们这个业务管理器,就会命令我们已经调了的这两个服务,去主动触发 它 它们的 Cancel 逻辑。Cancel 逻辑还是我们自己编写的,相当于我们给 它来做一个补偿。

比如原来我给这个里边加二了,我就给 它减二,原来我增添了这条记录,那我现在就给 它删除这条记录,这都是要我们自己写方法。

那这种模式呢在我们其实商城项目里边,特别是我们互联网项目。用的也非常多,支持 TCC 事务的框架也非常多。我们只需要按照人家规定的接口,把我们一个业务代码拆成三个部分就行了。

然后呢,人家会在合理的时机来触发我们哪个部分的逻辑。

所以我们只需要写好我们的回滚逻辑,最重要的就是这个事务补偿逻辑

你在这加二了,你最终呢就要减二来进行一个补偿。

你在这儿增添数据了,你最终就要删除数据来做一个补偿。

这就是 TCC 事务补偿方案。

3、柔性事务-最大努力通知方案

最大努力通知和下面的可靠消息都是用来保证最终一致性的

我们来举一个例子,我们现在有一个订单服务、 还有一个库存服务、还有一个大业务,大业务呢现在调了订单和库存,结果大业务在自己这失败了。然后 它就尽最大的努力通知库存去解锁

它调用一次库存解锁方法,不成了再调一次,再不成了,再调一次。这是我们自己写的同步的调用代码。

既然叫通知,我们就可以改成这样的逻辑,比如订单、库存都执行完了,但是它在下边做我们这个用户积分扣减的时候失败了。

然后接下来订单模块就可以来发一个消息,我们叫努力通知。我们发一个消息给我们的 MQ,接下来我们订单服务、库存服务都来订阅我们的这个消息队列。

而且我们两个服务都能同时收到消息。我们现在应该是 Topic 发布订阅模式。

我们现在两个服务呢都收到了,相当于大订单的创建失败消息。

然后我们库存服务收到这个消息就去解锁库存,

订单服务收到这个消息,就去解锁订单。

什么叫最大努力通知?

就是我们害怕这个订单服务,不知道我们这个消息,就是我们这个消息发出去了,我们害怕 它没收到,万一这个宕机了,一直收不到,那怎么办呢?那这块就失败了。

所以我们隔一秒给它里边发一个消息,说我失败了。再隔三秒,我发个消息,我说我失败了。再隔五秒我发一个消息,我说我失败了,我一直告诉你,我失败了、我失败了……

你哪一次真正的收到我失败了这个消息,而且你把你的业务执行成功了,你就可以告诉我,说行了我知道你失败了,你不用再通知我了。

这是我们说的最大努力通知型方案。

这个特别是我们在后来开发支付宝的时候,我们要支付订单,订单最终支付到底是成功了还是没成功?

支付宝呢对我们就是要最大努力通知,支付宝一会给我们发一个消息,说你这个成了,一会给你发一个消息,说你这个成了,一会儿发一个消息,当然消息是发给我们订单这个业务的。

4、柔性事务- 可靠消息+最终一致性方案(异步确保型)

其实跟最大努力通知方案一模一样

怎么能允许大并发呢?

就是我干完事了,我不用管你的状态,我发一个消息就行了。你在后边,你自己慢慢同步去。所以我们只要希望系统能达到最终的一致就行。

以上几种方案的总结

3、4这两种方案的最大好处,就是可以允许大并发

当然1、2这两种方案,我们后来也会有相应的使用场景。

我们分布式事务呢可以用框架 2PC 或者 3PC 或者我们的 TCC 模式。 TCC 呢相当于我们 3PC 的手动版。

3PC 相当于自动准备数据、自动预提交、自动回滚等等。

但是 TCC 相当于把这些自动搞的东西都给整成手动的。

我们自己写业务逻辑,我们可以用这种一失败以后,就立即能帮我们让其它业务都失败的一致性方案。

我们也可以利用消息队列完成我们的这些通知型方案,无论是最大努力通知,还是我们失败了,我们就发一个消息,我通知你一下。

这都是我们分布式系统里边解决分布式事务,我们常用的方案。