不就是分布式事务,这下彻底清楚了(1)

本文探讨了分布式事务中的不同解决方案,包括2PC、3PC、TCC和Saga,以及阿里巴巴开源的Seata。文章详细解释了这些协议的工作原理、优缺点和实际应用,强调了它们在最终一致性与性能之间的权衡。
摘要由CSDN通过智能技术生成

我们的分布式事务通常也做不到本地事务那么强的一致性,一般都是对一致性(Consistency)适当做了一些放宽,只需要达到最终的一致性。

分布式事务解决方案

===========================================================================

XA /2PC两阶段提交


XA

XA是一个分布式事务协议,由Tuxedo提出。

在这个协议里,有三个角色:

  • AP(Application):应用系统(服务)

  • TM(Transaction Manager):事务管理器(全局事务管理)

  • RM(Resource Manager):资源管理器(数据库)

XA规范主要定义了 事务管理器(Transaction Manager)和资源管理器(Resource Manager)之间的接口。

XA规范

XA协议采用两阶段提交方式来管理分布式事务。XA接口提供资源管理器与事务管理器之间进行通信的标准接口。

2PC 两阶段提交

两阶段提交的思路可以概括为: 参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情况决定各参与者是否要提交操作还是中止操作。

两阶段提交的两个阶段:第一阶段:准备阶段,第二阶段:提交阶段

两阶段-参考[2]

准备阶段 Prepares

协调者向所有参与者询问是否可以执行提交操作,所有参与者执行事务,将结果返回给协调者。

第一阶段

提交阶段 commit

  • 如果第一阶段汇中所有参与者都返回yes响应,协调者向所有参与者发出提交请求,所有参与者提交事务

  • 如果第一阶段中有一个或者多个参与者返回no响应,协调者向所有参与者发出回滚请求,所有参与者进行回滚操作

第二阶段

两阶段提交优点:尽量保证了数据的强一致,但不是100%一致

两阶段提交同样有一些缺点:

  • 单点故障

由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞,尤其时在第二阶段,协调者发生故障,那么所有的参与者都处于锁定事务资源的状态中,而无法继续完成事务操作。

  • 同步阻塞

它是一个强一致性的同步阻塞协议,也就是所谓刚性事务,事务执⾏过程中需要将所需资源全部锁定,会比较影响性能。

  • 数据不一致

在第二阶段中,当协调者想参与者发送提交事务请求之后,由于网络抖动,如果第二阶段只有部分参与者收到提交请求,那么就会导致数据不一致。

3PC 三阶段提交


三阶段提交(3PC)是二阶段提交(2PC)的一种改进版本 ,为解决两阶段提交协议的单点故障和同步阻塞问题。上边提到两阶段提交,当协调者崩溃时,参与者不能做出最后的选择,就会一直保持阻塞锁定资源。

2PC 中只有协调者有超时机制,3PC 在协调者和参与者中都引入了超时机制,协调者出现故障后,参与者就不会一直阻塞。而且在第一阶段和第二阶段中又插入了一个预提交阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。

三阶段提交的三个阶段:CanCommitPreCommitDoCommit三个阶段

三阶段协议-参考[2]

准备阶段 CanCommit

协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。

预提交阶段 PreCommit

协调者根据参与者在准备阶段的响应判断是否执行事务还是中断事务

  • 如果所有参与者都返回Yes,则执行事务

  • 如果参与者有一个或多个参与者返回No或者超时,则中断事务

参与者执行完操作之后返回ACK响应,同时开始等待最终指令。

提交阶段 DoCommit

协调者根据参与者在准备阶段的响应判断是否执行事务还是中断事务

  • 如果所有参与者都返回正确的ACK响应,则提交事务

  • 如果参与者有一个或多个参与者收到错误的ACK响应或者超时,则中断事务

  • 如果参与者无法及时接收到来自协调者的提交或者中断事务请求时,在等待超时之后,会继续进行事务提交

协调者收到所有参与者的ACK响应,完成事务。

3PC

可以看出,三阶段提交解决的只是两阶段提交中 单体故障和同步阻塞的问题,因为加入了超时机制,这里的超时的机制作用于 预提交阶段提交阶段。如果等待 预提交请求 超时,参与者直接回到准备阶段之前。如果等到提交请求超时,那参与者就会提交事务了。

无论是2PC还是3PC都不能保证分布式系统中的数据100%一致

TCC补偿事务


TCC Try-Confirm-Cancel 的简称,是两阶段提交的一个变种,针对每个操作,都需要有一个其对应的确认和取消操作,当操作成功时调用确认操作,当操作失败时调用取消操作,类似于二阶段提交,只不过是这里的提交和回滚是针对业务上的,所以基于TCC实现的分布式事务也可以看做是对业务的一种补偿机制。

TCC的三阶段:

  1. Try 阶段:对业务系统做检测及资源预留

  2. Confirm 阶段:对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功

  3. **Cancel 阶段:**在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放

在Try阶段,是对业务系统进行检查及资源预览,比如订单和库存操作,需要检查库存剩余数量是否够用,并进行预留,预留操作的话就是新建一个可用库存数量字段,Try阶段操作是对这个可用库存数量进行操作。

例如下单减库存的操作:

TCC下单减库存

执行流程:

  1. Try阶段:订单系统将当前订单状态设置为支付中,库存系统校验当前剩余库存数量是否大于1,然后将可用库存数量设置为库存剩余数量-1,

  2. 如果Try阶段执行成功,执行Confirm 阶段,将订单状态修改为支付成功,库存剩余数量修改为可用库存数量

  3. 如果Try阶段执行失败,执行Cancel 阶段,将订单状态修改为支付失败,可用库存数量修改为库存剩余数量

TCC 不存在资源阻塞的问题,因为每个方法都直接进行事务的提交,一旦出现异常通过则 Cancel 来进行回滚补偿,这也就是常说的补偿性事务。

但是,使用TCC,原本一个方法,现在却需要三个方法来支持,可以看到 TCC 对业务的侵入性很强,而且这种模式并不能很好地被复用,会导致开发量激增。还要考虑到网络波动等原因,为保证请求一定送达都会有重试机制,所以还需要考虑接口的幂等性。

本地消息表


本地消息表的核心思想是将分布式事务拆分成本地事务进行处理。

例如,可以在订单库新增一个消息表,将新增订单和新增消息放到一个事务里完成,然后通过轮询的方式去查询消息表,将消息推送到MQ,库存系统去消费MQ。

本地消息表

执行流程:

  1. 订单服务,添加一条订单和一条消息,在一个事务里提交

  2. 订单服务,使用定时任务轮询查询状态为未同步的消息表,发送到MQ,如果发送失败,就重试发送

  3. 库存服务,接收MQ消息,修改库存表,需要保证幂等操作

  4. 如果修改成功,调用rpc接口修改订单系统消息表的状态为已完成或者直接删除这条消息

  5. 如果修改失败,可以不做处理,等待重试

订单服务中的消息有可能由于业务问题会一直重复发送,所以为了避免这种情况可以记录一下发送次数,当达到次数限制之后报警,人工接入处理;库存服务需要保证幂等,避免同一条消息被多次消费造成数据不一致。

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

MQ消息事务


消息事务的原理是将两个事务通过消息中间件进行异步解耦。

订单服务执行自己的本地事务,并发送MQ消息,库存服务接收消息,执行自己的本地事务,乍一看,好像跟本地消息表的实现方案类似,只是省去 了对本地消息表的操作和轮询发送MQ的操作,但实际上两种方案的实现是不一样的。

消息事务一定要保证业务操作与消息发送的一致性,如果业务操作成功,这条消息也一定投递成功。

MQ消息事务

执行流程:

  1. 发送prepare消息到消息中间件

  2. 发送成功后,执行本地事务

  3. 如果事务执行成功,则commit,消息中间件将消息下发至消费端

  4. 如果事务执行失败,则回滚,消息中间件将这条prepare消息删除

  5. 消费端接收到消息进行消费,如果消费失败,则不断重试

消息事务依赖于消息中间件的事务消息,例如我们熟悉的RocketMQ就支持事务消息(半消息),也就是只有收到发送方确定才会正常投递的消息。

这种方案也是实现了最终一致性,对比本地消息表实现方案,不需要再建消息表,对性能的损耗和业务的入侵更小。

最大努力通知


最大努力通知相比实现会简单一些,适用于一些最终一致性要求较低的业务,比如支付通知,短信通知这种业务。

以支付通知为例,业务系统调用支付平台进行支付,支付平台进行支付,进行操作支付之后支付平台会去同步通知业务系统支付操作是否成功,如果不成功,会一直异步重试,但是会有一个最大通知次数,如果超过这个次数后还是通知失败,就不再通知,业务系统自行调用支付平台提供一个查询接口,供业务系统进行查询支付操作是否成功

最大努力通知

执行流程:

  1. 业务系统调用支付平台支付接口, 并在本地进行记录,支付状态为支付中

  2. 支付平台进行支付操作之后,无论成功还是失败,同步给业务系统一个结果通知

  3. 如果通知一直失败则根据重试规则异步进行重试,达到最大通知次数后,不再通知

  4. 支付平台提供查询订单支付操作结果接口

  5. 业务系统根据一定业务规则去支付平台查询支付结果

Saga事务


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

和本地事务undo log有点像,出问题了,逆向操作来挽救。

Sega简介:

  • Saga = Long Live Transaction (LLT,长活事务)

  • LLT = T1 + T2 + T3 + … + Ti(Ti为本地短事务)

  • 每个本地事务Ti 有对应的补偿 Ci

Sega的执行顺序:

  • 正常情况:T1 T2 T3 … Tn

  • 异常情况:T1 T2 T3 C3 C2 C1

Saga两种恢复策略

  • 向后恢复,如果任意本地子事务失败,补偿已完成的事务。如异常情况的执行顺序T1 T2 Ti Ci C2 C1.

  • 向前恢复,即重试失败的事务,假设最后每个子事务都会成功。执行顺序:T1, T2, …, Tj(失败), Tj(重试),…, Tn。

举个例子,假设用户下订单,花50块钱购买了10瓶可乐,则有这么一些短事务和回滚操作:

T1=下订单 => T2=用户扣50块钱 => T3=用户加10瓶可乐= > T4=库存减10瓶可乐

C1=取消订单 => C2= 给用户加50块钱 => C3 =用户减10朵玫瑰 = > C4=库存加10朵玫瑰

Sega事务

Seata


看了这么些事务的方案,介绍了相关的原理,但是这些原理怎么落地呢?各种各样的坑怎么处理呢?

—— 人生苦短,我用开源。

阿里巴巴开源了一套开源分布式事务解决方案——Seata。Seata可能并不称之为完美,但对代码入侵性非常小,基本环境搭建完成的话,使用的时候在只需要方法上添加一个注解@GlobalTransactional就可以开启全局事务。

Seata 也是从两段提交演变而来的一种分布式事务解决方案,提供了 ATTCCSAGAXA 等事务模式,我们来看一下AT模式。

Seata 中主要有这么几种角色:

TC(Transaction Coordinator):事务协调者。管理全局的分支事务的状态,用于全局性事务的提交和回滚。

TM(Transaction Manager):事务管理者。用于开启、提交或回滚事务。

RM(Resource Manager):资源管理器。用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或者回滚分支事务。

我们看一下Seata大概的一个工作流程:

Seata
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

分享一些资料给大家,我觉得这些都是很有用的东西,大家也可以跟着来学习,查漏补缺。

《Java高级面试》

《Java高级架构知识》

《算法知识》

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

分享一些资料给大家,我觉得这些都是很有用的东西,大家也可以跟着来学习,查漏补缺。

《Java高级面试》

[外链图片转存中…(img-Q2zwSjnV-1713444465562)]

《Java高级架构知识》

[外链图片转存中…(img-NjGHksEz-1713444465562)]

《算法知识》

[外链图片转存中…(img-PQ6cwchn-1713444465562)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值