小言_互联网的博客

详解 分布式事务

350人阅读  评论(0)

什么是分布式事务

跨多个数据库执行的事务叫 分布式事务,分布式事务 是用来保证分布式环境下 事务一致性的技术方案。如:分库分表、服务拆分时,各数据库被部署在不同的机器上,需要分布式事务来保证 这种情况的事务一致性。

X/Open DTP 分布式事务处理模型

X/Open DTP (X/Open Distributed Transaction Processing Reference Model) 分布式事务(处理参考)模型 是由 X/Open 组织定义的一套分布式事务的标准,也就是定义了规范和API接口,具体实现交由各个 IT厂商。

三大组件

X/Open DTP 定义了三个组件: AP,TM,RM。

  • AP(Application Program):也就是应用程序,可以理解为使用 分布式事务 的程序;
  • RM(Resource Manager):资源管理器,可以理解为一个 数据库系统,且该数据库系统必须实现 XA协议;
  • TM(Transaction Manager):事务管理器,负责协调和管理事务。

其中,AP 可以和TM 以及 RM 通信,TM 和 RM 之间也可以通信,DTP模型中定义了 XA协议,TM 和 RM 通过 XA协议 进行双向通信,例如:TM 通知 RM 提交事务或者回滚事务,RM 把提交结果通知给 TM。三者的关系如下图所示。

另外,在DTP中还定义了以下几个概念。

  • 全局事务:一次性操作多个数据库资源的事务,即 一个完整的分布式事务;
  • 分支事务:在一个全局事务中,各个数据库系统 有自己独立的事务,被称为 这个全局事务 的 分支事务。

2PC 两阶段提交协议

2PC 即 two phase commit,它定义了分布式事务的两阶段提交协议,如下。

  • 准备阶段:事务管理器 通知 数据库系统 准备分支事务,数据库返回准备结果;
  • 提交阶段:事务管理器 通知 数据库系统 提交分支事务,数据库返回提交结果。
    如果在 准备阶段 某个数据库 准备事务失败,提交阶段 就回滚 准备阶段开启的事务。

解决方案

分布式事务的实现主要有 5 种方案,XA 方案、TCC 方案、本地消息表、可靠消息最终一致性方案、最大努力通知方案。

XA 方案

基于 2PC (两阶段提交协议),事务管理器TM 负责协调多个数据库(资源管理器RM)的事务,事务管理器 先询问各个数据库是否准备好了事务,如果每个数据库都回复 ok,那么就正式提交事务;如果任何其中一个数据库回答 no,那么就回滚事务。

这种分布式事务方案,比较适合单块应用里,跨多个库的分布式事务,因为它严重依赖 数据库层面来搞定 分布式事务,效率很低,不适合高并发场景。

这个方案很少使用,一般来说,某个系统内部出现跨多个库的操作 是不合规的。现在的微服务架构 要求每个服务只能操作自己对应的一个数据库,如果你要操作其它服务对应的库,你必须是通过调用别的服务的接口来实现,绝对不允许直接访问别人的数据库。

TCC 方案

TCC 的全称是:Try、Confirm、Cancel。

  • Try 阶段:对各个服务的资源做检测以及对资源进行锁定或者预留;
  • Confirm 阶段:在各个服务中执行实际的操作;
  • Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,对其它服务的事务进行回滚。
    这种方案严重依赖于 开发者自己通过代码来实现,较为复杂,且代码难于维护。

一般来说,跟钱相关的 如:支付、交易等场景,我们会用 TCC,严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性。

本地消息表

本地消息表 是 ebay 搞出来的一套方案,大概意思是:

  • A 系统在自己本地一个事务里操作,同时插入一条数据到消息表;
  • 接着 A 系统将这个消息发送到 MQ 中去;
  • B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息;
  • B 系统执行成功之后,就会更新自己本地消息表的状态以及 A 系统消息表的状态;
  • 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到 MQ 中去,让 B 再次处理。
    这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止。但这个方案最大的问题在于,严重依赖于数据库的消息表来管理事务,不适用于高并发场景。

最终一致性方案

直接基于 MQ 来实现事务,如阿里的 RocketMQ 就支持消息事务。大概的意思是:

  • A 系统先发送一个 prepared消息 到 MQ,如果这个 prepared消息 发送失败那么就直接取消操作,否则执行本地事务;
  • 如果 本地事务执行成功,就发送确认消息到 MQ,否则 就发送回滚消息到 MQ;
  • 如果发送了确认消息,那么 B 系统会接收到确认消息,执行本地事务,否则回滚事务;
  • 如果 B系统 的事务失败了,就不断重试 直到成功,如果实在是不行,要么就针对重要的资金类业务进行回滚,比如 B 系统本地回滚后,想办法通知系统 A 也回滚;或者是发送报警由人工来手工回滚和补偿。
    这个方案比较合适 目前国内的互联网公司,大部分会考虑使用 RocketMQ 来支持消息事务。

最大努力通知方案

这个方案的大致意思就是:

  • 系统 A 本地事务执行完之后,发送个消息到 MQ;
  • 这里会有个专门消费 MQ 的最大努力通知服务,用于消费 MQ 然后写入数据库中记录下来,或者是放入某个内存队列,接着调用系统 B 的接口;
  • 如果系统 B 执行成功就 ok;否则,尽最大努力反复调用系统 B,若最后还是不行 就放弃。

转载:https://blog.csdn.net/qq_38038396/article/details/105472768
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场