分布式事务

什么是分布式事务

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器「分别位于不同的分布式系统的不同节点之上」

一个大的操作由N多的小的操作共同完成。而这些小的操作又分布在不同的服务上。针对于这些操作,「要么全部成功执行,要么全部不执行」

为什么会有分布式事务

在这里插入图片描述
上图中包含了库存和订单两个独立的微服务,每个微服务维护了自己的数据库。在交易系统的业务逻辑中,一个商品在下单之前需要先调用库存服务,进行扣除库存,再调用订单服务,创建订单记录。

正常情况下,两个数据库各自更新成功,两边数据维持着一致性。

但是,在非正常情况下,有可能库存的扣减完成了,随后的订单记录却因为某些原因插入失败。这个时候,两边数据就失去了应有的一致性。

在「单体应用」中,我们只需要贴上@Transactional注解就可以开启事务来保证整个操作的「原子性」

但是看似以上简单的操作,在实际的应用架构中,不可能是单体的服务,我们会把这一系列操作交给「N个服务」去完成,也就是拆分成为「分布式微服务架构」

比如下订单服务,扣库存服务等等,必须要「保证不同服务状态结果的一致性」,于是就出现了分布式事务。

分布式理论

https://blog.csdn.net/qxhly/article/details/119907327

分布式事务解决方案

两阶段提交(2PC)

熟悉mysql的同学对两阶段提交应该颇为熟悉,mysql的事务就是通过「日志系统」来完成两阶段提交的。
两阶段协议可以用于单机集中式系统,由事务管理器协调多个资源管理器;也可以用于分布式系统,「由一个全局的事务管理器协调各个子系统的局部事务管理器完成两阶段提交」
在这里插入图片描述

事务的提交分成两个阶段:
第一阶段,作为事务协调者的节点会首先向所有的参与者节点发送Prepare请求。在接到Prepare请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。如果参与者执行成功,暂时不提交事务,而是向事务协调节点返回“完成”消息。

当事务协调者接到了所有参与者的返回消息,整个分布式事务将会进入第二阶段。
在这里插入图片描述
第二阶段,如果事务协调节点在之前所收到都是正向返回,那么它将会向所有事务参与者发出Commit请求。

接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。
当事务协调者接收到所有事务参与者的“完成”反馈,整个分布式事务完成。

以上所描述的是两阶段提交的正向流程,接下来我们看一看失败情况的处理流程:
第一阶段
在这里插入图片描述
第二阶段
在这里插入图片描述
第一阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。于是在第二阶段,事务协调节点向所有的事务参与者发送Abort请求。接收到Abort请求之后,各个事务参与者节点需要在本地进行事务的回滚操作,回滚操作依照Undo Log来进行。

两阶段提交的不足

  • 性能问题, 响应时间较长: 整个消息链路是串行的,要等待响应结果,不适合高并发的场景
  • 单点故障:事务协调者是核心,一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知,参与者会一直处于中间状态无法完成事务。
  • 丢失消息导致的不一致问题:在第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。
三阶段提交(3PC)

三阶段提交又称3PC,相对于2PC来说增加了CanCommit阶段和超时机制。如果段时间内没有收到协调者的commit请求,那么就会自动进行commit,解决了2PC单点故障的问题

但是性能问题和不一致问题仍然没有根本解决。下面我们还是一起看下三阶段流程的是什么样的?

三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制。一旦事物参与者迟迟没有接到协调者的commit请求,会自动进行本地commit。这样有效解决了协调者单点故障的问题。但是性能问题和不一致的问题仍然没有根本解决。

补偿事务(TCC)

TCC其实就是采用的补偿机制,其核心思想是:「针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作」。它分为三个阶段:

  • Try阶段主要是对「业务系统做检测及资源预留」,其主要分为两个阶段
  • Confirm 阶段主要是对「业务系统做确认提交」,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
  • Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,「预留资源释放」。

比如下一个订单减一个库存:
在这里插入图片描述

  • Try阶段:订单系统将当前订单状态设置为支付中,库存系统校验当前剩余库存数量是否大于1,然后将可用库存数量设置为库存剩余数量-1
  • 如果Try阶段「执行成功」,执行Confirm阶段,将订单状态修改为支付成功,库存剩余数量修改为可用库存数量
  • 如果Try阶段「执行失败」,执行Cancel阶段,将订单状态修改为支付失败,可用库存数量修改为库存剩余数量

TCC 事务机制相比于上面介绍的2PC,解决了其几个缺点:

  • 「解决了协调者单点」,由主业务方发起并完成这个业务活动。业务活动管理器也变成多点,引入集群
  • 「同步阻塞」:引入超时,超时后进行补偿,并且不会锁定整个资源,将资源转换为业务逻辑形式,粒度变小。
  • 「数据一致性」,有了补偿机制之后,由业务活动管理器控制一致性

总之,TCC 就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,并且很大程度的「增加」了业务代码的「复杂度」,因此,这种模式并不能很好地被复用。

本地消息表

在这里插入图片描述
执行流程:

  • 消息生产方,需要额外建一个消息表,并「记录消息发送状态」。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。
  • 消息消费方,需要「处理」这个「消息」,并完成自己的业务逻辑。
    • 如果是「业务上面的失败」,可以给生产方「发送一个业务补偿消息」,通知生产方进行回滚等操作
    • 此时如果本地事务处理成功,表明已经处理成功了
    • 如果处理失败,那么就会重试执行
  • 生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。
Sagas 事务模型

Saga事务模型又叫做长时间运行的事务

其核心思想是「将长事务拆分为多个本地短事务」,由Saga事务协调器协调,如果正常结束那就正常完成,如果「某个步骤失败,则根据相反顺序一次调用补偿操作」

Seata框架中一个分布式事务包含3种角色:
Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚
Transaction Manager(TM ):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议
Resource Manager (RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

seata框架「为每一个RM维护了一张UNDO_LOG表」,其中保存了每一次本地事务的回滚数据。

具体流程:

  • 首先TM 向 TC 申请「开启一个全局事务」,全局事务「创建」成功并生成一个「全局唯一的 XID」
  • .XID 在微服务调用链路的上下文中传播
  • RM 开始执行这个分支事务,RM首先解析这条SQL语句,「生成对应的UNDO_LOG记录」。下面是一条UNDO_LOG中的记录,UNDO_LOG表中记录了分支ID,全局事务ID,以及事务执行的redo和undo数据以供二阶段恢复
  • RM在同一个本地事务中「执行业务SQL和UNDO_LOG数据的插入」。在提交这个本地事务前,RM会向TC「申请关于这条记录的全局锁」
    • 如果申请不到,则说明有其他事务也在对这条记录进行操作,因此它会在一段时间内重试,重试失败则回滚本地事务,并向TC汇报本地事务执行失败。
  • RM在事务提交前,「申请到了相关记录的全局锁」,然后直接提交本地事务,并向TC「汇报本地事务执行成功」。此时全局锁并没有释放,全局锁的释放取决于二阶段是提交命令还是回滚命令
  • TC根据所有的分支事务执行结果,向RM「下发提交或回滚」命令
    • RM如果「收到TC的提交命令」,首先「立即释放」相关记录的全局「锁」,然后把提交请求放入一个异步任务的队列中,马上返回提交成功的结果给 TC。异步队列中的提交请求真正执行时,只是删除相应 UNDO LOG 记录而已
  • RM如果「收到TC的回滚命令」,则会开启一个本地事务,通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。将 UNDO LOG 中的后镜与当前数据进行比较
    • 如果不同,说明数据被当前全局事务之外的动作做了修改。这种情况,需要根据配置策略来做处理。
    • 如果相同,根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句并执行,然后提交本地事务达到回滚的目的,最后释放相关记录的全局锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值