Day432.BASE理论&分布式事务常见解决方案 -谷粒商城

Posted 阿昌喜欢吃黄桃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day432.BASE理论&分布式事务常见解决方案 -谷粒商城相关的知识,希望对你有一定的参考价值。

BASE 理论

一、BASE 简介

BASE 其实就是对 CAP 的延伸。

我们在保证 AP 的情况下,我们永远无法做到强一致,就是我们这个业务状态做不了强一致,

但是我们可以让它弱一致,也就是我们说的最终一致,强一致弱一致是对立概念

强一致,就是我们以前用的这种本地系统。我们就一个数据库,一台机器,我们一个代码在这操作好多数据。那操作完了要么都成功,要么都失败。这是一个强一致状态

但我们在分布式以后呢,我们想要保证强一致可能很难。

但是我们可以保证最终一致,这就是我们说的 BASE,BASE 解释起来就是这个样子。


二、基本可用(Basically Available)

也就是说我们这个业务系统基本能用就行了,我们可以让它损失部分的可用性。比如说有两三个机器宕机了,我们可以损失一些部分的功能,或者我们也可以让他损失一些响应时间。

本来呢他不宕机,我查他挺快的,他宕机了,我查他不行了,我多查几个其他机器,查询速度慢一点也行,

所以我们最终都是希望一两个节点的不可用,不会导致我们整个系统不可用

所以我们肯定想要让我们整个系统都是可用的,我们可以让它响应时间上有损失,多试几次也可以让它功能上有损失

比如我们这个网站在高峰期的时候,我们为了保护我们系统的稳定性,我们可能将部分的消费者流量直接引导到一个错误页面,就是我们说的这个降级页面。当前服务排队人太多了,请稍后重试等等。所以这就是我们说的基本可用。我们要保证业务的基本能用

然后再加上我们的软状态。


三、软状态( Soft State)

软状态就指的是我们系统存在中间状态,不像我们的强一致,要么成要么败,我们也可以有一个中间状态。类似正在同步中这样。

比如我们保存了一个数据,它要么有,要么没有,但是还有一个正在同步中。我们可以有一个中间状态。

然后我们希望最终一致


四、最终一致( Eventual Consistency)

最终一致指的就是我们这个系统里边的这些数据。经过一段时间后,最终达到业务状态是一致的。

比如我们这个下单方法。

我们这个库存扣了,订单回滚了,库存没办法回滚,我们总是有一个东西呢没办法回滚,那没办法回滚怎么办呢?

我们首先不要求强一致了,但是我可以让系统过一段时间对它做一个检查,检查以后发现,刚才扣的这个库存都没人用,那再重新给它加回来,

这样最终导致的就是你如果没有这个订单,我最终就不给你扣这个库存,但是我们不是说立马就不扣的,我们可以让它到达一个最终一致。

我们可以用各种手段来保证最终一致性。


五、总结

  • 强一致

    • 就是我们要求这个数据更新以后,立马就能被看到。那我们现在的本地事务,我们现在就是这种强一致状态
  • 弱一致

    • 就是我现在更新完了,可能有一段时间我还看不到,我能容忍部分的时间、或者部分的节点,我这更新成功了,只有这个数据库。
      更成功了。那其他库呢可能还没有成功,还正在同步中。我们就可以忍受这些正在同步中的过程。如果能忍受,我们就说我们这个事务
      可以做成一个弱一致性的事务。不是非要那么强的
  • 最终一致

    • 就是指我们这个弱一致,经过一段时间以后,我们肯定得把它原来的数据同步过来。

或者我们这个下单方法,原来扣了的库存,最终都得加上去。这就是我们说的最终一致性


分布式事务常见的解决方案

一、2PC 模式

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1、优点

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


2、缺点

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

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

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

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

3、总结

了解即可,使用非常少


二、3PC 模式

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

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

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

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

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

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


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

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

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

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

1、什么叫柔性事务?

  • 刚性事务

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

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

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

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

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

分别是这三个阶段

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

这就是 TCC 事务补偿方案。


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

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

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

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

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

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

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

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

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

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

什么叫最大努力通知?

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

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

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

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

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

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


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

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

  • 怎么能允许大并发呢?

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


六、以上几种方案的总结

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

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

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

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

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

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

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

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


以上是关于Day432.BASE理论&分布式事务常见解决方案 -谷粒商城的主要内容,如果未能解决你的问题,请参考以下文章

Day431.本地事务&分布式事务&CAP理论 -谷粒商城

Day431.本地事务&分布式事务&CAP理论 -谷粒商城

Day434.订单&库存服务分布式事务的最终解决 -谷粒商城

Day434.订单&库存服务分布式事务的最终解决 -谷粒商城

分布式事务 - 三种常见的解决方案

分布式事务---2PC和3PC理论