一、什么是分布式事务
首先我们知道本地事务是指事务方法中的操作只依赖本地数据库,可保证事务的ACID特性。而在分布式系统中,一个应用系统被拆分为多个可独立部署的微服务,在一个微服务的事务方法中,除了依赖本地数据库外,还可能会调用一个或多个远程服务操作远程数据库,这种就叫做分布式事务。
在分布式事务中,如果由于网络波动导致远程调用执行成功了,但是没有及时返回结果,导致事务回滚,本地数据库回滚了,但是远程数据库已经执行成功持久化了,这就出现了不一致的情况。
二、分布式理论
1. CAP理论
对于一个分布式系统来说,不可能同时满足以下三点:
- 一致性 (Consistency):同时访问所有节点时都能得到相同的最新数据副本。
- 可用性(Availability):每次请求都能获取到非错的响应,也就是说不会返回错误或者超时,但不能保证获取的数据为最
新数据。 - 分区容错性(Partition Tolerance):由于网络波动等原因,如果系统在限定通信时间内不能达到数据一致性,此时就发生了数据分区。分区容错性要求在发生数据分区时系统仍然能够正常运行。那么由于网络波动是必然存在的,要满足分区容错性显然就要从一致性和可用性中做出选择了。
为什么不能同时满足三点
比如说数据库的主从节点,当网络分区发生后,节点间的数据没办法及时同步,如果要保证强一致性,那么从节点必须要在主节点数据写入时就锁住,等待网络恢复数据同步完成后才能提供服务,这就牺牲了可用性。如果要保证可用性,那么未同步的节点提供的数据就不是最新的,这就牺牲了一致性。
2. Base理论
在CAP理论中的一致性强调的是强一致性。BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,我们称之为“柔性事务”。
BASE 包括Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个概念:
- 基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。如,电商网站交易付款出现问题了,商品依然可以正常浏览。
- 软状态:由于不要求强一致性,所以BASE允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用性,如订单的"支付中"、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。
- 最终一致性:最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。
前面已经学习了分布式事务的基础理论,以理论为基础,针对不同的分布式场景业界常见的解决方案有2PC、可靠消息最终一致性、最大努力通知这几种。
三、2PC —— 两阶段提交
2PC主要的模式分为以下三种
1. XA模式 —— 强一致性
-
P 准备阶段:事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undolog日志,但是先不提交事务,然后给事务管理器回复一个OK,表示准备好了。
-
C 提交阶段:如果所有参与者都准备好了,事务管理器就会发送一个commit消息,所有参与者再执行事务提交。如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息,所有参与者就都执行回滚。
即第一阶段参与者只执行不提交事务,第二阶段收到Commit信号后再进行提交(收到Rollback信号则根据undolog回滚)。
XA模式优缺点:XA模式保证了强一致性,但是资源锁需要等到两个阶段结束才释放,性能较差。
数据库一般本身支持XA模式的协议。也可以基于一些第三方框架比如Seata来实现。
2. AT模式 —— 弱一致性
-
一阶段:事务参与者收到消息后先记录修改前的数据,然后直接执行并提交事务,给事务管理器回复执行情况。
-
二阶段:都成功执行则事务管理器给所有参与者发送消息清除记录的数据,有失败或者超时则通知所有参与者根据记录的数据执行反向SQL补偿操作来回滚。
AT模式优缺点:AT模式在第一阶段就提交了事务释放了资源锁,性能较高。但是由于提前提交了事务,如果在回滚之前有其它事务读写了相关数据,那么再回滚后,就造成了脏读/脏写问题。
但这在大多数业务场景中不会造成影响,如果需要保证强一致性,Seata框架实现了一种自定义全局锁的解决方案:所有事务读写数据的时候先拿到相应的本地数据库锁,本地事务提交前需要额外拿到一个对所操作数据的全局锁(Seata中自定义的),分布式事务确认执行成功后再释放这个全局锁,这样就避免了脏读脏写问题,并且相对于XA模式,这样不需要等待上一个事务执行完毕释放本地锁,下一个事务才能读写,可以先进行读写操作,然后等待全局锁被释放即可,效率更高。
AT模式是Seata中的默认模式
3. TCC模式 —— 弱一致性
TCC模式分为一阶段的Try和二阶段的Confirm和Cancel,共三个操作
- 一阶段:事务参与者通过Try操作判断是否有可用数据,有则先预留事务操作需要的资源。
- 二阶段:如果全部Try成功则执行Confirm操作,完成资源的操作业务,且Try成功Confirm一定要成功,无论是通过重试还是人工介入。如果有Try失败的,则所有Try成功的节点执行Cancel操作释放预留资源。
以传统的订单、库存、账户服务为例,在 try 阶段尝试预留资源,插入订单、扣减库存、扣减金额,这三个服务都是要提交本地事务的,这里可以把资源转入中间表。在 commit 阶段,再把 try 阶段预留的资源转入最终表。而在 cancel 阶段,把 try 阶段预留的资源进行释放,比如把账户金额返回给客户的账户。
TCC模式优缺点: 性能较好。但Try、Confirm、Cancel需要人工手写,对代码具有一定侵入性。而且需要考虑幂等性、空回滚、悬挂判断,较为复杂、性能最好,但成本太高。
幂等性: try、confirm、canel这三个接口,要保证重试操作具有幂等性。通过一张本地“分支事务记录”来记录对一个分布式事务已经执行过程操作。
空回滚:没有执行try操作的节点回滚时执行了cancel。解决方案:用一张“分支事务记录”记录是否执行过try操作,执行cancel时要进行查询,执行过try操作才需要回滚。
悬挂:try操作由于网络波动超时了,导致触发回滚cancel操作,在执行完cancel后try操作请求到达了,这种先cancel再try的现象就称为悬挂。解决方案:在执行一阶段事务时判断在该全局事务下,“分支事务记录”表中是否已经有二阶段事务记录,如果有则不执行Try。
四、3PC —— 三阶段提交
事务一阶段执行前可能已经有某个节点故障不能执行此次任务,那其他节点就白白浪费资源去执行了,因此可以在2PC前再加一个确认阶段,确认所有节点是否正常,正常则再继续下面的2PC。
五、可靠消息最终一致性
可靠消息最终一致性方案是通过消息中间件完成的,指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能
够接收消息并处理事务成功,使得所有事务参与方最终事务达到一致。
要达成这种效果需要解决以下问题:
- 原子性:本地事务和消息发送必须同时成功或者同时失败,具有原子性。
- 可靠性:事务参与方必须能够在消息队列接收到消息,接收失败可以重复接收。
- 幂等性: 事务参与方不能重复消费消息。
1. 本地消息表
本地数据库增加一个消息表,将本地事务操作和添加消息记录放在同一个事务中,然后后台定时任务去循环扫描这个消息表,检测到未发送的消息时就交给MQ发送,消费端收到这个消息后通过MQ回复ACK确认,发送端收到MQ反馈后再删除对应的消息记录,消费端要对收到的消息进行幂等性检查避免重复消费(发送端可能会重复发送),非重复消费则消费执行事务。
2. RocketMQ事务消息方案
- 在执行事务前会先发消息给MQ服务端,但是这个消息是不可消费状态。
- 然后发送方再执行本地事务,执行成功/失败后再给MQ服务端发送一个commit或者rollback事务确认消息,如果执行成功了MQ服务端再把消息投递给订阅方,如果执行失败了则直接丢弃原来的消息。
- 如果确认消息在中间丢失了,MQ服务端没有收到 则会定期回查事务的状态。
在RocketMQ 4.3后实现了完整的事务消息,实际上其实是对本地消息表的一个封装,将本地消息表移动到了MQ 内部,解决 Producer 端的消息发送与本地事务执行的原子性问题。
六、最大努力通知
发起通知方通过一定的机制最大努力将业务处理结果通知到接收方,比如重复通知,并且发送方要提供消息校对接口,若尽最大努力仍没有通知到,此时可由接收方主动向通知方查询消息信息来满足需求。
1. MQ最大努力通知实现方案
- 发送方通过MQ将消息发送出去。接收方收到后会回复一个ack,发送方收到ack则通知成功了。
- 若发送方没有收到ack,则进行重传,直到超过一定次数。
- 接收方可主动通过发送方提供的接口进行消息校对,获取需要的消息。
参考:
- https://www.cnblogs.com/hongdada/p/16796704.html
- https://seata.apache.org/zh-cn/blog/seata-tcc-fence/
- https://www.bilibili.com/video/BV1Q4411y7ip
- https://blog.csdn.net/m0_58600248/article/details/126271252
- https://blog.csdn.net/O_Dentist/article/details/130966668