目录

一、两阶段提交

二、三阶段提交

三、TCC

四、最终一致性


一、两阶段提交

两阶段提交就是把分布式事务分为两个阶段,一个是准备阶段、另一个是提交阶段。

 1、两阶段提交协议的流程:

  • 准备阶段:协调者向参与者发起指令,参与者评估自己的状态,如果参与者可以执行事务,则会写入redo或者undo日志,然后锁定资源,执行操作,但不提交。
  • 提交阶段:如果每个参与者明确返回准备成功,也就是预留资源和执行操作成功,则协调者向参与者发起提交命令,参与者提交资源变更的事务,释放锁定资源,如果任何一个参与者明确返回准备失败,也就是预留资源或者执行操作失败,则协调者向参与者发起终止指令,参与者取消已变更的事务,执行undo日志,释放锁定的资源。

 2、两阶段提交执行流程图:

  • 成功场景:

    分布式事务解决方案汇总

  • 失败场景:

分布式事务解决方案汇总

3、两阶段提交问题:

  • 性能问题:对于任何一次指令都必须收到明确的响应,才会继续进行下一步,否则处于阻塞状态,占用的资源被一直锁定,不会被释放。
  • 单点故障:如果协调者宕机,参与者没有协调者指挥,则会一直阻塞,尽管可以通过选举新的协调者替代原有协调者,但是如果协调者在发送一个提交指令后宕机,而提交指令仅仅被一个参与者接收,并且参与者接收后也宕机,则新上任的协调者无法处理这种情况
  • 脑裂:协调者发送提交指令,有的参与者接收到并执行了事务,有的参与者没有接收到事务就没有执行事务,多个参与者之间是不一致的。

二、三阶段提交

1、三阶段提交流程

  • 询问阶段:协调者询问参与者是否可以完成指令,参与者只需回答是或不是,而不需要做真正的操作,这个阶段超时会导致终止。
  • 准备阶段:如果在询问阶段所有参与者都返回可以执行操作,协调者想参与者发送预执行请求,然后参与者写日志,执行操作但是不提交操作;如果在询问阶段任意参与者返回不能执行操作的结果,则协调者向参与者发送终止请求,这里的逻辑与两阶段提交协议的准备阶段相似。
  • 提交阶段:如果参与者在准备阶段返回成功,则协调者向参与者发起提交指令,参与者提交资源变更事务,释放锁定的资源;如果任何参与者返回准备失败,则协调者想参与者发起终止指令,参与者取消已经变更的事务。

2、三阶段提交流程示意图如下:

  • 成功情况

分布式事务解决方案汇总

  • 失败情况

分布式事务解决方案汇总

3、三阶段提交和两阶段提交的不同点

  • 三阶段提交增加了询问阶段,询问阶段可以确保尽可能早地发现无法执行操作而需要终止的行为,但是他并不能发现所有的这种行为,只会减少这种情况的发生。
  • 在准备阶段以后,协调者和参与者执行的任务中都增加了超时,一旦超时,则协调者和参与者都会继续提交事务,默认成功,这也是根据概率统计超时后默认成功的正确性最大。 

三、TCC

前面讲的2PC提交通常用来解决两个数据库之间的分布式事务,比较局限。为了解决两个应用之间的分布式事务,支付宝提出了TCC协议。TCC是Try、Confirm、Cancel三个单词的缩写,其实是一个应用层面的2PC协议,Confirm对应2PC中的事务提交操作,Cancel对应2PC中的事务回滚操作。

1、TCC的操作流程如下:

  • 准备阶段:调用方调用所有服务提供方的Try接口,该阶段各调用方做资源检查和资源锁定,为接下来的阶段2做准备。
  • 提交阶段:如果所有的服务方都返回了YES,则进入提交阶段,调用方调用各个服务的Confirm接口,各服务方进行事务提交。如果有一个服务方在阶段1返回NO或者超时了,则调用方调用个服务方的Cancel接口。

2、执行流程实例如下:

  • 事务提交示意图

分布式事务解决方案汇总

分布式事务解决方案汇总

  • 事务回滚示意图 

分布式事务解决方案汇总

3、TCC存在的问题 

当TCC中的服务宕机,或者超时时,调这会通过不停的进行重试来进行补偿,所有在服务提供者方需要保证幂等性。

四、最终一致性

     最终一致性,一般是通过消息中间件,当系统A执行了本地事务后,发送操作消息到消息中间件服务,当系统B收到消息数据库在执行系统B的本地事务,但是这存在一个问题就是,系统A执行成功后,往消息服务器发送消息失败,或者消息丢失,再或者系统B收到消息后执行本地事务出现异常等。

最终一致性的集中具体实现思路:

1、最终一致性:错误的方案0

把发送消息和执行本地操作放到一个事务中,如果消息发送失败则回滚本地事务,如果消息发送成功才执行本地事务,但是还会存在以下问题:

  • 网络2将军问题:发送消息失败,发送方并不知道是消息中间件没有收到消息,还是消息已经收到,只是在返回是出现了异常。
  • 把网络调用放在事务中,可能会因为网络的延迟导致数据库长事务。严重的会阻塞整个数据库,风险很大。

2、最终一致性:第一种实现方式(业务自己实现)

      如果消息中间件没有提供“事务消息”功能,

  • 系统A添加一张消息表,系统A不直接给消息中间件发送消息,而是把消息存入到本地消息表中,把插入消息表和系统A的操作放到一个事务中。
  • 系统A准备一个调度程序,查询消息表把为发送成功的消息发送到消息中间件中。消息中间件返回成功后更新消息表中消息为成功。
  • 问题1:消息丢失。系统B从消息中间件取出消息后,如果处理一半系统B宕机并再次重启。此种情况是通过消息中间件的ACK机制,当系统B消费并且操作执行成功后才给消息中间件发送ACK。
  • 问题2:重复消费,此种问题是需要系统B实现幂等性操作,解决重复消费问题。

此种方案的缺点:系统A增加消息表,同时添加了一个后台调度任务,不断扫描此消息表,会导致消息的处理和业务逻辑耦合,额外增加了业务方的开发负担。

3、最终一致性:第二种实现方式(基于RocketMQ事务消息)

RocketMQ提供了事务消息,把消息发送分为了消息预发送和确认发送两个阶段。具体使用方法如下:

  • 步骤1:系统A调用Prepare接口,预发送消息。此时消息保存在消息中间间中,但消息中间件不会把消息发送给消费方。
  • 步骤2:系统A更新数据库,进行操作。
  • 步骤3:系统A调用Confirm接口,确认发送消息。此时消息中间件才会把消息发送给消费方进行消费。

这种方式有两个异常场景:

  • 场景1:步骤1成功,步骤2成功,步骤3失败或超时。
  • 场景2:步骤1成功,步骤2失败或超时,步骤3不会执行。

RocketMQ的处理方式为:RocketMQ会定期扫描所有的预发送但还未确认发送的消息,回调发送方,询问这条消息是是要发送出去,还是取消。

4、人工介入

对出现异常的分布式事务生成预警信息,有人工进行核对,进行处理。

 

参考:

    《软件架构设计—大型网站技术架构与业务架构融合之道》——余春龙

     《分布式服务架构—原理、设计与实战》—— 李鹏艳,杨彪

相关文章:

  • 2022-12-23
  • 2021-07-28
  • 2022-01-11
  • 2021-09-17
猜你喜欢
  • 2021-10-19
  • 2021-12-26
  • 2021-12-27
  • 2021-04-20
相关资源
相似解决方案