【分布式基础】分布式事务解决方案

本文探讨了分布式事务的解决方案,包括两阶段提交的原理与问题,如同步阻塞和协调者单点故障。介绍了3PC的改进,以及TCC和SAGA模式在业务逻辑层面上的处理方法。还涉及了本地消息表和可靠消息服务的实现,以及尽最大努力通知的柔性事务模型。
摘要由CSDN通过智能技术生成

分布式事务解决方案

两阶段提交

两阶段提交,就是字面意思,分两阶段提交。有两个角色,一个负责协调各个本地资源的管理器 事务管理器,另一个便是本地资源管理器,一般是数据库。

事务管理器在第一阶段会向各个本地资源管理器发送一个 Prepare 消息,询问资源管理器是否准备就绪,如果事务管理器收到的回复都是 yes,则在第二阶段发送 commit 消息进行提交事务,如果其中任意一个资源管理器回复的是 no 则回滚事务。
在这里插入图片描述

在这里插入图片描述

2PC 存在的问题:

  • 同步阻塞:当参与事务者存在占用公共资源的情况,其中一个占用资源,其他事务参与者就只能阻塞等待资源释放

解决方案:引入超时机制,如果长时间没有收到响应,则执行特定的动作

  • 协调者单点故障:协调者在 2PC 中是非常重要的角色,如果协调者故障了,则整个系统会陷入瘫痪

解决方案:单点故障的常规解决方案即为引入多副本机制,在主节点挂掉之后重新选主

  • 数据不一致:在阶段二,如果事务管理器只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。

三阶段提交 (3PC)

三阶段提交的提出主要是为了解决两阶段提交中的一些问题。三阶段提交,顾名思义就是事务要提交需要经历三个阶段,3PC 是将 2PC 的第一阶段分成了两个阶段,canCommit 和 preCommit

与 2PC 相比,3PC 是在 2PC 的第一阶段和第二阶段中间插入了一个 准备阶段,确保事务在提交之前各个参与节点的状态保持一致。

第一阶段,协调者会向各个参与者发送 CanCommit 消息,参与者根据自身状态返回是否可以参与事务

第二阶段,如果所有的参与者在第一阶段都回复了 yes 则向参与者发送 PreCommit,参与这接收到消息后进行事务的执行操作但是不提交。如果有任何一个参与者回复了 no 则进行回滚

第三阶段,如果第二阶段的参与者都执行完了事务操作,会返回 ACK,协调者收到所有的 ACK 后向各个参与者发送 DoCommit 进行事务的提交。并在完成事务提交之后释放所有事务资源,事务提交完之后,向协调者发送Ack响应。若有参与者回复了 no 则发送事务的回滚消息。

3PC 解决 2PC 的问题:

降低同步阻塞:引入了参与者超时机制,解决了资源占用问题

提升了数据一致性:

  1. 2PC 中有一种情况会导致数据不一致,当协调者向参与者发送 Commit 消息之后,发生了网络异常,一部分参与者收到了 commit 消息进行了事务的提交,但是有一部分参与者没有收到 Commit 消息,事务未提交,于是发生了数据不一致,这种情况下,3PC 可以很好的解决,因为参与者没有收到协调者的提交事务的消息的时候,不会一直阻塞,过一段时间后它会自动提交事务。
  2. 2PC 中还有一种情况,在协调者发出 Commit 消息之后当宕机了,而唯一接收到这个 Commit 消息的参与者也宕机了,那么即使协调者通过选举重新选出了协调者,那么这条事务的状态也是不确定的,这种情况下,3PC 的解决方案是,在重新选举了协调者之后,协调者可以询问参与者状态,如果有一个参与者处于 commit 或者 preCommit 状态那么就通知所有的参与者提交事务。

3PC 无法解决的问题

在 DoCommit 阶段,如果有参与者迟迟收不到协调者的 DoCommit 或者是 Abort 消息,那么这个参与者会在一段时间后自动提交事务,但是如果协调者发送的是 Abort 消息的话,那么就会造成数据的不一致。

TCC(Try-Confirm-Cancle)

TCC 是从业务逻辑层面处理,不依赖于底层的数据资源的事务支持,当然很多情况都是两者的配合:

  • 一阶段 try,执行业务层面自定义的 Prepare 逻辑,也就是 try 阶段,try 阶段定义为执行执行资源的锁定

    例如 A 要向 B 转账 100 元,而余额系统和转账系统分别为两个系统,那么 try 阶段要做的就是检查 A 账户的余额是否足够,减去转账金额存入临时字段,做到余额的锁定,将流水状态设置为交易中

  • 二阶段 confirm,执行业务层面自定义的 Commit 逻辑,也就是 confirm 阶段,confirm 阶段的定义为执行 try 阶段锁定的资源,也就是所基于 try 的成功,可以继续操作

    confirm 阶段要做的就是向 B 的余额中加入 100 元,并将流水状态修改为交易完成

  • 二阶段 cancle,执行业务层面的 rollback,也就是 cancle 阶段,cancle 阶段定义为释放 try 阶段的资源,也就是说,如果 try 阶段失败了,要做出相应的补偿操作回复环境

    当 try 阶段失败了,会执行 cancle 阶段,将 A 余额存入 100 元。并将流水状态设置为交易失败

SAGA

Saga 模式主要用于长事务解决方案,业务流程中每个参与者都提交本地事务,当某一参与者失败,则补偿前面的参与者,一阶段正向服务和二阶段补偿服务都由业务来开发。

适用场景

  • 业务流程长、业务流程多
  • 参与者包含其他公司遗留的系统服务,无法提供 TCC 模式的三个接口

Saga 主要思想是依赖于状态机转换,长事务拆分成多个短事务,依次执行短事务,如果某个短事务失败,则按照前面执行顺序的逆序执行补偿事务

本地消息表

本地消息表有两个角色,生产者A 和 消费者B:

  1. 当系统 A 被其他系统调用发生数据库的更新时,系统A 首先会更新自己的业务表,并在自己数据库中的消息表中添加一条记录,这两个操作在一个事务流程中
  2. 系统 A 的脚本会定期轮询本地消息表,将新的消息封装后写进 MQ,如果消息发送失败则重试
  3. 消费者系统B,消费 MQ 中的消息,并处理业务逻辑。如果本地事务处理失败,会继续消费 MQ 中的消息进行重试,如果自身业务失败,则通知系统 A 进行回滚操作

可靠消息服务

实现流程

  1. 事务发起方向 MQ 中发送 半事务消息
  2. MQ 回复半事务消息发送成功
  3. 事务发起方执行本地事务
  4. 本地事务执行成功发送 commit 消息到 MQ,本地事务执行失败发送 rollback 消息到 MQ ,MQ 会删除对应的半事务消息
  5. 若 MQ一段时间内没有收到半事务消息的状态消息,也就是第四步,那么 MQ 会主动向事务发起方查询事务状态,事务发起方将事务的状态返回给 MQ
  6. 事务发起方向 MQ 发送 commit 后,事务参与方即可消费 MQ 中的半事务消息,并执行事务,若事务执行失败会重试,执行完毕后返回 ack 给 MQ

优点

  • 消息数据独立存储,降低了业务系统与消息系统之间的耦合性
  • 吞吐量优于本地消息列表

缺点

  • 一次消息发送需要两次网络请求(半事务消息和 commit/rollback)
  • 需要实现消息回查接口

尽最大努力通知

尽最大努力通知是一种柔性事务,适用于一些最终一致性并且一致性时间敏感度低的场景,且事务参与方的处理结果不影响事务发起方的的处理结果。

大致流程如下:

  1. 事务发起方执行完本地事务后,向MQ中发送一个消息
  2. 有一个专门消费 MQ 消息的服务,该服务会调用事务参与者的接口
  3. 若是事务参与者执行成功就 ok,若不成功,那么就定时尝试重新调用事务参与者的接口n次,若还失败就放弃
  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值