分布式事务的五种解决方案

分布式事务

微服务分布式服务问题

传统的单体应用(Monolithic App),通过 3 个 Module,在同一个数据源上更新数据来完成一项业务。很自然的,整个业务过程的数据一致性由本地事务来保证。但是在微服务中单体应用被拆成了微服务,每个服务都是一个分别使用单独的一个数据源。三个服务之间通过RPC实现业务调用。
每一个服务内部的数据一致性仍由本地事务来保证。而整个业务层面的全局数据一致性要如何保障呢?这就是微服务架构下面临的,典型的分布式事务需求:我们需要一个分布式事务的解决方案保障业务全局的数据一致性。

什么是分布是事务

分布式事务就是为了保证不同数据库的数据一致性。
什么是分布式系统:部署在不同节点上的系统通过网络交互来完成协同工作的系统。

分布式事务应用在哪些场景

电商系统中的下单扣库存 电商系统中,订单系统和库存系统是两个系统,一次下单的操作由两个系统协同完成…等

分布式事务解决方案

1.XA两段提交(低效率)-分布式事务解决方案
2.TCC三段提交(2段,高效率[不推荐(补偿代码)])
3.本地消息(MQ+Table)
4.事务消息(RocketMQ[alibaba])
5.Seata(alibaba) (我们使用的就是它)

1.基于XA协议的两阶段提交(2PC)

基于XA协议的两段提交(低效率)-分布式事务解决方案

二阶段提交2PC(Two phase Commit)是指,在分布式系统里,为了保证所有节点在进行事务提交时保持一致性的一种算法。
在分布式系统里,每个节点都可以知晓自己操作的成功或者失败,却无法知道其他节点操作的成功或失败。
当一个事务跨多个节点时,为了保持事务的原子性与一致性,需要引入一个协调者(Coordinator)来统一掌控所有参与者(Participant)的操作结果,并指示它们是否要把操作结果进行真正的提交(commit)或者回滚(rollback)。

2PC顾名思义分为两个阶段,其实施思路可概括为:
(1)投票阶段(voting phase):参与者将操作结果通知协调者
(2)提交阶段(commit phase):收到参与者的通知后,协调 者再向参与者发出通知,根据反馈情况决定各参与者是否要提交还是回滚;
它的缺点就是:
算法执行过程中,所有节点都处于阻塞状态,所有节点所持有的资源(例如数据库数据,本地文件等)都处于封锁状态。
2PC效率很低,分布式事务很难做
在分布是中的具体的缺陷:

2PC两阶段提交究竟有哪些不足呢?

  1. 性能问题 2PC遵循强一致性。在事务执行过程中,各个节点占用着数据库资源,只有当所有节点准备完毕,事务协调者才会通知提交,参与者提交后释放资源。这样的过程有着非常明显的性能问题。
  2. 协调者单点故障问题 2PC模型的核心,一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知,参与者会一直处于中间状态无法完成事务。
  3. 丢失消息导致的不一致问题。 第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。

总结:两阶段提交就是 1.就是当协调者向参与者发送请求之后,当参与者收到请求之后执行对应的操作但是不进行提交事务,而是向协调者发送完成或者失败的消息。2.第二阶段就是协调者拿到不同的参与者的反馈后进行判断如果有一个失败则继续发送消息给参与者都进行回滚,如果都成功的话就发送消息都提交,他的缺点就是性能各个节点会占用资源,存在单点故障问题(一旦事务的协调者挂掉的话就无法完成事务),各个参与者的如果有一个存在局部网络问题的话会导致各个节点之间数据不一致的问题。

2.代码补偿事务(TCC)

TCC是Try ( 尝试 ) — Confirm(确认) — Cancel ( 取消 ) 的简称。TCC的作用主要是解决跨服务调用场景下的分布式事务问题
场景:在这里插入图片描述此场景下保证两张都能买到 预留其实就是在尝试,如果预留成功后可以确保两边都可以确认成功,任何一个确认失败两边都需要取消。
TCC总结:
TCC的缺点就是开发的代码量会比较大,需要写三个接口。比起XA的优点是它不是长时间的去占有锁,当try结束后就会释放锁可以让其他事务使用,而XA则是一直占用直到事务执行结束之后才会释放。
TCC两阶段提交与XA两阶段提交的区别

XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
TCC核心在于将业务分为两个操作步骤完成。不依赖 RM 对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。所以开发量较大,需要提供Try/Confirm/Cancel接口。

3.本地消息表(异步确保)- 事务最终一致性

这种实现方式的思路,其实是源于 ebay,后来通过支付宝等公司的布道,在业内广泛使用。其基本的设计思想是将远程分布式事务拆分成一系列的本地事务。如果不考虑性能及设计优雅,借助关系型数据库中的表即可实现。
在这里插入图片描述本地消息表通过将消息放到事务里完成,然后轮询去查询消息表,将消息推送到MQ,,然后去另一个系统中去消费MQ

本地消息表这种方案实现了最终一致性,需要在业务系统里增加消息表,业务逻辑中多一次插入的 DB 操作,所以性能会有损耗,而且最终一致性的间隔主要由定时任务的间隔时间决定。

优点: 一种非常经典的实现,避免了分布式事务(这里我们只有两个本地事务),实现了最终一致性。 缺点:
消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

总结:添加一个本地消息表和一个mq消息队列,如图所示的步骤中当5修改状态的时候故障的时候就会导致消息表这里一直收不到状态码的消息这时候就会导致不停的轮询发送消息导致库存不停的在变,如何解决这个问题呢我们可以使用乐观锁去解决。

4.MQ 事务消息

使用的消息队列必须支持事务操作我们使用的是RocketMQ
RocketMQ事务消息分为两条主线

定时任务发送流程:发送half message(半消息),执行本地事务,发送事务执行结果
定时任务回查流程:MQ服务器回查本地事务,发送事务执行结果
在这里插入图片描述具体流程如下
1、Producer 向 MQ 服务器 发送消息 , MQ Server 将消息状态标记为 Prepared(预备状态),注意此时这条消息消费者(MQ订阅方)是无法消费到的。
2、MQ 服务器收到消息并持久化成功之后,会向Producer 确认首次消息发送成功,此时消息处于 half message(半消息) 状态,并未发送给对应的 Consumer 。
3、Producer 开始执行本地事务逻辑 , 通过本地数据库事务控制。
4、根据事务执行结果,Producer 向 MQ 服务器提交二次确认 ( commit 或rollback) 。MQ Server 收到 Commit 状态则将半消息标记为可投递,Consumer 最终将收到该消息;MQ Server 收到 Rollback 状态则删除半消息,Consumer 将不会接受该消息。
5、在断网或者应用重启的情况下,二次确认未成功的发给 MQ Server,MQ Server 会主动向 Producer 启动消息回查
6、Producer 根据事务执行结果,对消息回查返回对应的结果。
7、Mq Server根据返回结果,决定继续投递消息或者丢弃消息(重复第4步操作)。
注意 1-4 为事务消息的发送过程, 5-6 为事务消息的回查过程。

总体流程总结:首先消息发送放发送一个half消息告诉MQ服务器我有一个事务要准备操作了,当MQ服务器给消息发送方回复一个消息的成功的消息的时候,然后发送方开始执行本地事务,发送发会判断自己的事务执行成功或者失败,然后发送一个消息给消息队列告诉消息队列提交或者回滚,如果是提交的话这时候的half消息就变成了全消息。然后就会去接收消息方的本地执行事务操作,但是如果是回滚的话,消息队列就会将half消息删掉,当发送方执行结束后发送给消息队列提交或者回滚的消息的时候因为网络或者其他问题导致发送失败的话,消息队列会有一个回查本地事务的机制

优点: 实现了最终一致性,不需要依赖本地数据库事务。
缺点: 目前主流MQ中只有RocketMQ支持事务消息。
本地消息表和MQ事务消息的区别

本地消息表方案中,生产者需要额外创建消息表,还需要对本地消息表进行轮询,业务负担较重。阿里开源的RocketMQ
4.3之后的版本正式支持事务消息,该事务消息本质上是把本地消息表放到RocketMQ上,解决生产端的消息发送与本地事务执行的原子性问题。 事务消息方案与本地消息表机制非常类似,区别主要在于原先相关的本地表操作替换成了一个反查接口

5. Seata(AT及MT) *(重点)

我们的微服务分布式中主要使用的是seate中的AT模式
seate又称简单可扩展自治事务框架。
解决分布式事务问题,有两个设计初衷

1.对业务无侵入:即减少技术架构上的微服务化所带来的分布式事务问题对业务的侵入

2.高性能:减少分布式事务解决方案所带来的性能消耗

Seata中有两种分布式事务实现方案,AT及MT(TCC)

AT模式主要关注多 DB 访问的数据一致性,当然也包括多服务下的多 DB 数据访问一致性问题 2PC-改进 TCC
模式主要关注业务拆分,在按照业务横向扩展资源时,解决微服务间调用的一致性问题

Seata 的设计思路是将一个分布式事务可以理解成一个全局事务,下面挂了若干个分支事务,而一个分支事务是一个满足 ACID 的本地事务,因此我们可以操作分布式事务像操作本地事务一样。
AT模式(Automatic (Branch) Transaction Mode)

Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并决定全局事务的提交或回滚。
Transaction Manager(TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
Resource Manager (RM):资源管理器,负责本地事务的注册,本地事务状态的汇报(投票),并且负责本地事务的提交和回滚。
XID:一个全局事务的唯一标识

其中,TM是一个分布式事务的发起者和终结者,TC负责维护分布式事务的运行状态,而RM则负责本地事务的运行。
在这里插入图片描述
下面是一个分布式事务在Seata中的执行流程:

  1. TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID
  2. XID 在微服务调用链路的上下文中传播。
  3. RM 向 TC 注册分支事务,接着执行这个分支事务并提交(重点:RM在第一阶段就已经执行了本地事务的提交/回滚),最后将执行结果汇报给TC
  4. TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。
  5. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
    Seata 中有三大模块,分别是 TM、RM 和 TC。 其中 TM 和 RM 是作为Seata 的客户端与业务系统集成在一起,TC 作为 Seata 的服务端独立部署

总结:
流程就是TM需要发送请求的时候首先向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID,然后这个XID会在微服务调用的整个链路中赋给每一个微服务,每个微服务的RM会去TC(seate)中注册分支事务,然后会执行分支事务并且提交这里是关键执行完事务之后就会直接提交,然后将结果汇报给TC,TM根据TC的中所有分支的执行情况发起全局的提交或者回滚。最终使全部的分支都完成提交或者回滚的操作

MT模式(Manual (Branch) Transaction Mode)Seata还支持MT模式。MT模式本质上是一种TCC方案,业务逻辑需要被拆分为 Prepare/Commit/Rollback 3 部分,形成一个 MT 分支,加入全局事务。如图所示:
在这里插入图片描述

MT 模式一方面是 AT 模式的补充。另外,更重要的价值在于,通过 MT 模式可以把众多非事务性资源纳入全局事务的管理中。
就相当与将steate和微服务都注册到Nacos中就可以使得steate直接访问Nacos中的微服务

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值