分布式事务模型--XA Specification

本文来说下分布式事务模式–XA Specification

文章目录

  • 概述
  • XA Specification
    • 预备阶段
    • 提交/回滚阶段
    • 特点剖析
  • 本文小结


概述

事务是一组不可分组的操作集合,这些操作要么都成功执行,要么都取消执行。最典型的需要事务的场景是银行账户间的转账:假如 A 账户要给 B 账户转账 100 元,那么 A 账户要扣减 100 元,B 账户要增加 100 元,这两个账户的数据变更都成功才可算作转账成功。更严格来说,可以用 ACID 四个特性表述事务:

  • Atomicity:原子性,事务中的所有操作要么都成功执行,要么都取消执行,不能存在部分执行,部分不执行的状态。
  • Consistency:一致性,举个例子简单的理解就是,A、B 两个账户各有 100 元,无论两个账户并发相互转账多少次,两个账户的资金总额依然是 200 元。
  • Isolation:隔离性,并发事务之间的相互影响程度,隔离性也是分级别的:读未提交、读已提交、可重复读等。
  • Durability:持久性,事务完成后对数据的更改不会丢失。

单体数据库不涉及网络交互,所以在多表之间实现事务是比较简单的,这种事务我们称之为本地事务。

但是单体数据库的性能达到瓶颈的时候,就需要分库(分物理实例),就会出现跨库(数据库实例)的事务需求;随着企业应用的规模越来越大,企业会进一步进行服务化改造,以满足业务增长的需求;当前微服务架构越来越流行,跨服务的事务场景也会越来越多。

这些都是分布式事务的需求。分布式事务是指是指事务的发起者、参与者、数据资源服务器以及事务管理器分别位于分布式系统的不同节点之上。

概括起来,分布式事务有三种场景:

  • 跨数据库分布式事务
  • 跨服务分布式事务
  • 混合式分布式事务

分布式事务模型--XA Specification_第1张图片
分布式事务中涉及的参与者分布在异步网络中,参与者通过网络通信来达到分布式一致性,网络通信不可避免出现失败、超时的情况,因此分布式事务的实现比本地事务面临更多的困难。下面介绍几种常见的分布式事务解决方案。本篇先介绍第一种XA Specification,其他的后续会继续介绍。


XA Specification

一套分布式事务标准,使用了两阶段提交来保证分布式事务的完整性。

最早的分布式事务产品可能是 AT&T 在 20 世纪 80 年代推出的 Tuxedo (Transactions for Unix, Extended for Distributed Operations),Tuxedo 最早是为了电信领域的 OLTP 系统研发的分布式事务中间件,后来标准化组织 X/Open 吸收采纳了 Tuxedo 的设计思想和一些接口,推出了分布式事务规范:XA Specification。

XA 规范中定义了分布式事务处理模型,这个模型中包含四个核心角色:

  • RM (Resource Managers):资源管理器,提供数据资源的操作、管理接口,保证数据的一致性和完整性。最有代表性的就是数据库管理系统,当然有的文件系统、MQ 系统也可以看作 RM。
  • TM (Transaction Managers):事务管理器,是一个协调者的角色,协调跨库事务关联的所有 RM 的行为。
  • AP (Application Program):应用程序,按照业务规则调用 RM 接口来完成对业务模型数据的变更,当数据的变更涉及多个 RM 且要保证事务时,AP 就会通过 TM 来定义事务的边界,TM 负责协调参与事务的各个 RM 一同完成一个全局事务。
  • CRMs (Communication Resource Managers):主要用来进行跨服务的事务的传播。

下图是 XA 规范中定义的事务模型图,其中:发起分布式事务的 TM 实例称之为 root 节点,其他的 TM 实例可以统称为事务的参与者。事务发起者负责开启整个全局事务,事务参与者各自负责执行自己的事务分支。如果TM实例发起了对其他 TM 实例的服务调用,那么发起者就被成为 Superior,被调用这就被称之为 Subordinate 节点。

分布式事务模型--XA Specification_第2张图片
XA 规范中分布式事务是构建在 RM 本地事务(此时本地事务被看作分支事务)的基础上的,TM 负责协调这些分支事务要么都成功提交、要么都回滚。XA 规范把分布式事务处理过程划分为两个阶段,所以又叫两阶段提交协议(two phrase commit)


预备阶段

TM 记录事务开始日志,并询问各个 RM 是否可以执行提交准备操作。

RM 收到指令后,评估自己的状态,尝试执行本地事务的预备操作:预留资源,为资源加锁、执行操作等,但是并不提交事务,并等待 TM 的后续指令。如果尝试失败则告知 TM 本阶段执行失败并且回滚自己的操作,然后不再参与本次事务(以 MySQL 为例,这个阶段会完成资源的加锁,redo log 和 undo log 的写入)。

TM 收集 RM 的响应,记录事务准备完成日志。


提交/回滚阶段

这个阶段根据上个阶段的协调结果发起事务的提交或者回滚操作。

如果所有 RM 在上一个步骤都返回执行成功,那么:

  • TM 记录事务 commit 日志,并向所有 RM 发起事务提交指令。
  • RM 收到指令后,提交事务,释放资源,并向 TM 响应“提交完成”。
  • 如果 TM 收到所有 RM 的响应,则记录事务结束日志。

如果有 RM 在上一个步骤中返回执行失败或者超时没有应答,则 TM 按照执行失败处理,那么:

  • 记录事务 abort 日志,向所有 RM 发送事务回滚指令。
  • RM 收到指令后,回滚事务,释放资源,并向 TM 响应回滚完成。
  • 如果 TM 收到所有 RM 的响应,则记录事务结束日志。

分布式事务模型--XA Specification_第3张图片

针对部分场景,XA 规范还定义了如下优化措施:

  • 如果 TM 发现整个事务只涉及到一个 RM,那么就会将整个过程退化为一阶段提交。
  • 如果 RM 收到的 AP 的数据操作是只读操作,那么它可以在阶段 1 就将事务完成并告知 TM 其不再参与阶段 2 的过程。会有脏读的风险。
  • 如果 RM 在阶段1完成后,长时间等不到阶段 2 的指令,那么其可以自动提交或者回滚本地事务。这叫做 Heuristic Completion,注意这种场景有可能会破坏事务的一致性,产生异常。

XA 规范中详细定义了各个核心组件之间的交互接口,以 TM 和 RM 的交互接口为例,如下图,一次完整的全局事务,TM 和 RM 之间的交互还是比较频繁的:

分布式事务模型--XA Specification_第4张图片

事务的执行过程中,宕机和网络超时都有可能发生,针对这些异常场景,不同 XA 规范的实现,对异常处理做法可能不同,可参考如下:

  • TM 在阶段 1 中询问 RM 前宕机,恢复后无需做任何操作。
  • TM 在阶段 1 中询问 RM 后宕机,可能只有部分 RM 收到了阶段 1 的请求,因此此时需要向 RM 发起回滚请求。
  • TM 在阶段 1 中询问 RM 完毕,但是在就准备完成日志时宕机,因不清楚宕机前的事务协商的结果,因此恢复后需要向 RM 发起回滚请求。
  • TM 在阶段 1 中记录完毕事务准备完成日志后宕机,恢复后可以根据日志发起提交或者回滚的指令。
  • TM 在阶段 2 中记录 commit/abort 日志前宕机,恢复后可以根据日志发起提交或者回滚指令。
  • TM 在阶段 2 中记录事务结束日志前宕机,恢复后可以根据日志发起提交或者回滚指令。
  • TM 在阶段 2 中记录事务结束日志后宕机,恢复后无需做任何操作。
  • 阶段 1 中,RM 有超时情况时,TM 按失败处理,给所有 RM 发送回滚指令。
  • 阶段 2 中,RM 有超时情况是,TM 需要对超时的 RM 持续重复发送指令。

特点剖析

XA 两阶段提交协议设计上是要像本地事务一样实现事务的 ACID 四个特性:

  • 原子性:在 prepare 和 commit 阶段保证事务是原子性的。
  • 一致性:XA 协议实现的是强一致性。
  • 隔离性:XA 事务在完成之前一直持有资源的锁,所以可以做到写隔离。
  • 持久性:基于本地事务实现,所以这一点没有问题。

XA 是出现最早的分布式事务规范,主流数据库 Oracle、MySQL、SQLServer 等都支持 XA 规范,J2EE 中的 JTA 规范也是参照 XA 规范编写的,与 XA 规范兼容

XA 是在资源管理层面实现的分布式事务模型,对业务的入侵度较低。

XA 两阶段提交协议可以覆盖分布式事务的三种场景,但是全局事务的执行过程中,RM 一直持有资源的锁,如果参与的 RM 过多,尤其是跨服务的场景下,网络通信的次数和时间会急剧变多,所以阻塞的时间更长,系统的吞吐能力变得很差,事务死锁出现的概率也会变大,所以并不适合微服务架构场景中的跨服务的分布式事务模式。

每一个 TM 域来说,由于 TM 是单点,存在单点故障风险,如果 TM 在阶段1之后挂掉,会导致参与的 RM 长时间收不到阶段 2 的请求而长期持有资源的锁,影响业务的吞吐能力。同时一次完整的全局事务,TM 和 RM 之间的交互多达 8 次,太繁琐,非常影响系统的处理性能。

XA 两阶段协议可能会造成脑裂的异常,假如 TM 在阶段 2 通知 RM 提交事务时,如果指令发出后就宕机了,而只有部分 RM 收到了提交请求,那么当 TM 恢复的时候,就无法协调本次事务所有的 RM 本地事务的一致性了。

XA 要处理的异常场景非常多,对框架的实现有一定的挑战,开源的实现,可以参考:Atomikos,Bitronix。

针对 XA 两阶段提交中的问题,有人提出了三阶段提交的改进方案,三阶段提交方案主要解决了单点故障问题,并在 RM 侧也引入了超时机制,以避免资源的长时间锁定。但是三阶段提交方案依然无法避免脑裂的异常情况出现,实际应用案例很少,感兴趣的同学可以自行找相关资料了解。


本文小结

本文详细介绍了分布式事务模式之XA Specification,这也是分布式事务最初的解决方案。后面会对其他更加成熟的解决方案来进行介绍。

你可能感兴趣的:(核心知识点,分布式,分布式,大数据,数据库)