你必须了解的分布式事务解决方案
前言
温馨提示:文章很干,请多喝水
什么是事务想必大多数朋友应该都很清楚了,不清楚的可以看前面的文章《》。
分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
简单来说,就是一个大的操作由 N 个小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。比如存在一个订单的微服务,一个库存的微服务,当订单完成需要同步减少库存,这时候就要在事务上确保完整和一致。
CAP 理论
-
一致性(Consistency):在分布式系统完成某写操作后任何读操作,都应该获取到该写操作写入的那个最新的值。相当于要求分布式系统中的各节点时时刻刻保持数据的一致性。 -
可用性(Availability): 一直可以正常的做读写操作。简单而言就是客户端一直可以正常访问并得到系统的正常响应。用户角度来看就是不会出现系统操作失败或者访问超时等问题。 -
分区容错性(PartitionTolerance):指的分布式系统中的某个节点或者网络分区出现了故障的时候,整个系统仍然能对外提供满足一致性和可用性的服务。也就是说部分故障不影响整体使用。事实上我们在设计分布式系统是都会考虑到 bug、硬件、网络等各种原因造成的故障,所以即使部分节点或者网络出现故障,我们要求整个系统还是要继续使用的
CP:放弃可用性,注重一致性和分区容错性,其实这就是所谓的强一致性,可能在银行跨行转账这种强一致业务场景才会用到,具体得根据业务场景做取舍。
AP:放弃强一致性,注重可用性和分区容错性,这是现在绝大多数分布式业务场景的选择,只要最后能保证最终一致性( BASE 理论)即可。
-
基本可用(Basically Available):基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现。 -
软状态 ( S oft State):软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。MySQL Replication 的异步复制也是一种体现。 最终一致性 ( E ventual Consistency):最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。
1、两阶段提交
-
准备阶段( Prepare Phase ): 首先协调器会向所有的参与者发送准备提交或者取消提交的请求,然后会收集参与者的决策。 -
提交阶段(Commit Phase): 协调者会收集所有参与者的决策信息,当且仅当所有的参与者向协调器发送确认消息时协调器才会提交请求,否则执行回滚或者取消请求。
2PC 存在的问题:
同步阻塞:所有的参与者都是事务同步阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
单点故障:一旦协调者发生故障,系统不可用。
数据不一致:当协调者发送 commit 之后,有的参与者收到 commit 消息,事务执行成功,有的没有收到,处于阻塞状态,这段时间会产生数据不一致。
不确定性:当协调者发送 commit 之后,并且此时只有一个参与者收到了 commit,那么当该参与者与协调器同时宕机之后,重新选举的协调器无法确定该条消息是否提交成功。
2、三阶段提交
三阶段提交(Three-phase commit),简称为 3PC,是 2PC 的改进版本。同时在协调者和参与者都引入了超时机制,还在 2PC 中的准备阶段和提交阶段中间增加了一个预提交阶段。
-
准备阶段(CanCommit): 协调者向各个参与者发送请求,询问是否可以执行事务,但并不执行事务。 -
预提交阶段(PreCommit): 如果从协调者得到的反馈是满足执行条件,那么就发送预提交请求,并开始执行事务;如果从协调者得到的反馈是不满足执行条件或者超时,则发送事务中断请求。
-
提交阶段(DoCommit): 如果预提交阶段发送的是预提交请求,那么正常提交事务;如果预提交阶段发送的是事务中断请求,那么直接中断事务。
3、TCC
Try 阶段:完成所有业务检查(一致性),预留业务资源(准隔离性)
Confirm 阶段:确认执行业务操作,不再做任何业务检查, 只使用Try阶段预留的业务资源。
Cancel 阶段:取消Try阶段预留的业务资源。
-
幂等问题: 因为网络调用无法保证请求一定能到达,所以都会有重调机制,因此对于 Try、Confirm、Cancel 三个方法都需要幂等实现,避免重复执行产生错误。 -
空回滚问题: 指的是 Try 方法由于网络问题没收到超时了,此时事务管理器就会发出 Cancel 命令,那么需要支持 Cancel 在未执行 Try 的情况下能正常的 Cancel。 -
悬挂问题: 这个问题也是指 Try 方法由于网络阻塞超时触发了事务管理器发出了 Cancel 命令,但是执行了 Cancel 命令之后 Try 请求到了。所以空回滚之后还得记录一下,防止 Try 的再调用。
4、本地消息表
本地消息表分布式事务解决方案是国外的 eBay 提出的一套方案。其实就是利用了各系统本地的事务来实现分布式事务,在数据库中存放一张事务消息表,在执行业务操作的时候, 将业务的执行和将消息放入消息表中的操作放在同一个事务中。
5、可靠消息最终一致性方案
在服务 B 执行的过程中也可能会失败,这时也是需要重试,一直执行不成功也需要人工介入,同时也需要保证服务 B 方法的幂等性。
6、最大努力通知
最大努力通知型( Best-effort delivery)是最简单的一种柔性事务,适用于一些最终一致性时间敏感度低的业务,且被动方处理结果不影响主动方的处理结果。典型的使用场景:如银行通知、商户通知等。
就本地消息表来说会有后台任务定时去查看未完成的消息,然后去调用对应的服务,当一个消息多次调用都失败的时候可以记录下然后引入人工,或者直接舍弃。这其实算是最大努力了
事务消息也是一样,当半消息被commit了之后确实就是普通消息了,如果订阅者一直不消费或者消费不了则会一直重试,到最后进入死信队列。其实这也算最大努力。
最大努力通知,发起通知方尽最大的努力将业务处理结果通知为接收通知方,但是可能消息接收不到,此时需要接收通知方主动调用发起通知方的接口查询业务处理结果,通知的可靠性关键在接收通知方。
往期推荐