分布式事务

本文探讨了分布式事务的概念,介绍了CAP定律和BASE理论,详细解析了2PC、3PC协议以及Seata和TCC的解决方案,同时讨论了可靠消息最终一致性与最大努力通知的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分布式事务

概念:
是指一次大的操作由不同的小操作组成,并且这些小的操作分布在不同的服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败。从本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

CAP定律:
是指在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partitiontolerance(分区容错性)三者不可兼得。

BASE理论:
BASE是Basically Available(基本可用)、Soft state(软状态)、Eventually Consistent(最终一致性)三个短语的缩写。它是对CAP理论中一致性和可用性权衡的结果。
基本可用:
是指分布式系统在出现不可预知的故障的时候,允许损失部分可用性。比如延长响应时间,服务降级等。
软状态:
是指允许系统中的数据存在一个中间状态,并且认为该中间状态的存在不会影响系统的整体可用性,也就是说允许系统在不同节点的数据副本之间进行数据同步的时候存在延时。
最终一致性:
强调的是所有的数据副本在经过一段时间的同步之后,最终都能够达到一个一致的状态

分布式事务解决方案:

2PC

两阶段提交协议,是将整个事务流程分为两个阶段,P是准备阶段,C是提交阶段。整个事务过程由事务管理器和参与者组成
准备阶段: 事务管理器会给每个参与者发送Prepare消息,每个参与者在本地执行事务,并写本地的undolog和redolog日志,undolog记录修改前的数据,用于数据库回滚。redolog记录修改后的数据,用于提交事务后写入数据文件
提交阶段: 如果事务管理器收到了参与者执行失败或超时的消息时,直接给每个参与者发送回滚消息,否则发送提交消息;参与者再根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的资源。
优点:它可以利用数据库自身提供的事务特性来进行提交或回滚,几乎不会有业务侵入
缺点:会造成同步阻塞,协调者单点故障,网络分区导致的数据不一致等问题。
解决方案:
1、超时机制:如果协调者在规定时间内没有收到参与者的反馈,协调者就会认为这个事务失败了,并通知其他参与者进行回滚操作
2、心跳机制:协调者会每隔一定时间向参与者发送消息来检测这个参与者是否存活,如果在规定时间里没有收到参与者的响应,那么就可以认为这个参与者挂掉了,从而执行一些回滚操作
3、预备性提交:在第一阶段协调者可以通知参与者进行预备性提交,并在得到所有参与者的预备性提交确认后,将事务提交请求发送给所有参与者。如果在第二阶段中协调者没有收到某个参与者的确认消息,那么这个时候可以向该参与者发送回滚消息。
4、使用备份协调者防止协调者单点故障,备份协调者可以监控协调者的状态,在协调者失效时接替其工作。
5、消息队列:参与者可以将事务日志写入消息队列,协调者可以从消息队列中获取事务日志,如果协调者在处理事务时失效,备份协调者可以继续从消息队列里获取消息,并继续进行处理。

3PC

三阶段提交协议
CanCommit阶段: 协调者会向所有参与者发送CanCommit请求,询问是否可以执行事务提交操作,如果可以返回yes,否则返回no。如果协调者从所有参与者处得到的反馈都是yes,就会进入第二阶段PreCommit阶段进行事务的预提交。如果有一个事务参与者返回了no或等待超时,此时协调者会向所有参与者发送abort请求,参与者收到abort请求或超时之后仍未收到协调者的请求时,就会执行事务的中断。
PreCommit阶段: 协调者会向参与者发送PreCommit请求,参与者在接收到请求之后,会执行事务操作,并记录undolog和redolog,事务执行成功之后会返回ACK响应。如果协调者没有收到参与者的ACK响应,就会进行事务中断,此时协调者会向所有参与者发送abort请求,并根据undolog和redolog进行事务回滚并在回滚完成之后释放所有的事务资源。参与者完成事务回滚之后会再向协调者发送ACK消息,协调者接收到ACK之后执行事务的中断。
DoCommit: 如果协调者收到了第二阶段中所有参与者事务执行成功返回的ACK后,会向所有参与者发送doCommit请求,参与者收到请求之后执行正式的事务提交,在完成事务提交之后向协调者发送ACK响应并释放所有事务资源,协调者收到所有参与者的ACK响应之后完成事务。

2PC和3PC的区别:
1、3PC比2PC多了一个CanCommit阶段,减少了不必要的资源浪费。因为2PC在第一阶段会占用资源,而3PC在这个阶段不占用资源,只是校验一下,如果不能执行直接返回
2、超时机制
2PC只有协调者有超时机制,超时后会发送回滚指令
3pc协调者和参与者都有超时机制,协调者的超时机制是在cancommit和precommit阶段中如果没有收到参与者的反馈,则发送中断指令
参与者的超时机制是在precommit阶段如果没有收到协调者的指令就进行回滚,在docommit阶段如果没有收到协调者的指令就进行提交。

Seata

TC:事务协调者。维护全局和分支事务的状态,驱动全局事务提交或回滚
TM:事务管理器。定义全局事务的范围:开始全局事务,提交或回滚全局事务
RM:资源管理器。管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
AT模式(最终一致性):
它是由二阶段提交协议演变而来的,在第一阶段中Seata会拦截业务SQL并写下undo log,然后执行业务sql更新数据,更新之后再写下redo log,最后生成行锁,这些操作都是在本地数据库事务内完成,保证了一阶段的原子性。第二阶段是负责整体的回滚和提交,如果之前的一阶段中有本地事务没有通过,那么就执行全局回滚,否则执行全局提交,并且释放所有资源和删除所有日志。
XA模式(强一致性):
SAGA:
SAGA模式只能通过状态机引擎来实现,通过状态图来定义服务调用的流程并生成json配置文件,状态图中的一个节点可以调用一个服务,节点可以配置他的补偿节点,状态图json有状态机引擎驱动执行,当出现异常时状态机引擎反向执行已成功节点对应的补偿节点将事务进行回滚。

TCC

也是二阶段提交协议,它是一种侵入式的分布式事务解决方案,包含三个操作try、confirm、cancel,try是对业务资源进行检查并预留,confirm是对业务进行提交,cancel是对业务进行取消,这三个阶段都需要业务系统自行实现,对业务系统有着非常大的侵入性,但它可以完全不依赖数据库,能够实现跨数据库、跨应用的资源管理
TCC空回滚:
是为了解决在没有调用try方法的情况下,调用了cancel方法,导致的数据不一致问题。关键就是看try是否执行,解决方案就是增加一张分支事务记录表,其中有全局事务ID和分支事务ID。如果当前事务执行了try就在表中生成一条记录,否则不生成。在执行cancel的时候去数据库里查一下有没有执行try操作,如果执行了就正常回滚,如果没执行就进行空回滚
幂等:
同一个操作无论执行多少次,其结果都是一样的。
因为TCC二阶段中的confirm和cancel都有重试机制,为了保证重试机制不会引发数据不一致,所以就要保证try、confirm和cancel接口的幂等。解决方案就是在执行try、confirm或cancel方法时向分支事务记录表中增加一条记录,当方法再次执行的时侯都去查一下分支事务表中有没有相应的记录,如果有就说明已经执行过。
如何解决TCC中的悬挂问题:
悬挂就是在分布式事务中,在调用分支事务try时,由于网络拥堵造成超时,导致二阶段的cancel接口比try接口先执行。
解决方案就是在进行一阶段事务时判断在该全局事务下,分支事务表中是否已经有二阶段事务记录,如果有则不执行try。

可靠消息最终一致性

是指当事务发起方执行完本地事务后发出一条消息,事务参与方一定能够接收消息并处理事务成功
在这里插入图片描述
由于事务发起方和消息中间件之间,事务参与方与消息中间件之间都是通过网络通信,由于网络通信的不确定性就会导致分布式事务问题。
因此可靠消息最终一致性方案需要解决以下几个问题:
1、本地事务与消息发送的原子性问题
2、事务参与方接收消息的可靠性
3、消息重复消费问题

解决方案1:本地消息表方案
它的核心就是通过本地事务保证业务操作和消息发送的一致性,然后通过定时任务将消息发送到消息中间件,等确认消息成功发送给消费方之后再将消息删除。
比如现在有A、B两个服务,A服务在成功执行完自己本地事务的同时,会将发送给B服务的消息保存到A服务的消息日志表中。然后再A服务中启动一个定时任务来扫描消息日志表,将没有发送的消息发送到MQ,即使MQ挂了,定时任务也会一直扫描一直发,直到成功为止。这就保证了本地事务与消息发送的原子性。之后B服务会去监听消息队列,获取消息并成功消费之后向MQ发送ack,否则MQ就不断重试向B服务发送消息。所以B服务中的接口还要实现幂等。
缺点:需要在数据库端轮询扫描消息表,对数据库性能有一定影响。

解决方案2:RocketMQ事务消息方案
它实际是对本地消息表的一个封装,只是将本地消息表移动到了MQ内部,解决了本地事务与消息发送的原子性问题。
在这里插入图片描述
它的执行流程是:
1、消息的发送方会先向消息队列发送一个半消息,
2、消息队列成功接受到消息之后在给消息发送方返回一个接收成功的消息,
3、消息发送方收到反馈之后会执行本地事务
4、如果本地事务执行成功,则会向消息队列发送commit消息,否则发送回滚消息
5、如果消息队列收到的是commit消息,就会将之前的半消息投递给消费者,如果收到的是回滚消息就会删除之前的半消息不进行投递
6、如果消息队列长时间没有收到消息发送方的commit或回滚消息就会回查事务状态(RocketMQLocalTransactionListener),然后根据事务状态来决定是否投递消息。

最大努力通知

是指通知发起方通过一定的机制尽最大的努力将业务处理结果通知到接收方,如果接收方接收不到可以通过业务回查接口查询业务执行结果
消息重复通知机制
消息校对机制
方案1: 使用MQ的ack机制来实现最大努力通知
在这里插入图片描述
执行流程:
通知发起方使用普通消息机制将通知发送到MQ,通知接收方监听MQ,如果接收方接收到通知并成功处理则回应ack给MQ,否则MQ会重复通知,最后通知接收方可以通过消息校对接口来校对消息的一致性

方案2: 也是通过MQ的ack机制来实现,与方案一不同的是,它是由专门的通知程序来监听MQ,再将业务处理结果通过互联网接口协议发送给通知接收方。
在这里插入图片描述
方案1适用于内部应用之间的通知,方案2适用于外部应用之间的通知,比如支付宝和微信支付的支付结果通知,
如果你做了一个电商系统需要对接支付宝或微信支付,别人肯定不能让你监听他们的MQ。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值