《深入理解分布式事务》第七章 XA 强一致性分布式事务原理

本文深入探讨了XA强一致性分布式事务原理,包括X/OpenDTP模型、XA规范、JTA规范及MySQL对XA的支持等内容,并讨论了XA规范存在的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《深入理解分布式事务》第七章 XA 强一致性分布式事务原理

一、X/Open DTP 模型与 XA 规范

X/Open DTP 模型是 X/Open 组织定义的分布式事务标准规范,这个规范定义了分布式事务处理的一套规范和 API,具体的实现由各厂商负责。本节对 X/Open DTP 模型与 XA 规范进行简单介绍

1.DTP 模型

DTP 模型主要定义了 3 个核心组件,分别是应用程序、资源管理器和事务管理器,三者之间的关系如下图所示:

在这里插入图片描述

  • 应用程序用于定义事务边界,即定义事务的开始和结束,并且在事务边界内对资源进行操作
  • 资源管理器也称为事务参与者,如数据库、文件系统等,并提供访问资源的方式
  • 事务管理器也称为事务协调者,负责分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚等操作

2.XA 规范

下面简要介绍 XA 规范:

  1. xa_start:负责开启或恢复一个事务分支,并且管理 XID 到调用线程
  2. xa_end:负责取消当前线程与事务分支的关联
  3. xa_prepare:负责询问资源管理器是否准备好提交事务分支
  4. xa_commit:负责通知资源管理器提交事务分支
  5. xa_rollback:负责通知资源管理器回滚事务分支
  6. xa_revocer:负责列出需要恢复的 XA 事务分支

3.JTA 规范

JTA(Java Transaction API)为 J2EE 平台提供了分布式事务服务的能力。JTA 规范是 XA 规范的 Java 版,即把 XA 规范中规定的 DTP 模型交互接口抽象成 Java 接口中的方法,并规定每个方法要实现什么样的功能,其架构如下图所示:

在这里插入图片描述

JTA 定义的接口如下:

  1. javax.transaction.TransactionManager:事务管理器,负责事务的 begin、commit、rollback 等命令
  2. javax.transaction.UserTransaction:用于声明一个分布式事务
  3. javax.transaction.TransactionSynchronizationRegistry:事务同步注册
  4. javax.transaction.xa.XAResource:定义资源管理器提供给事务管理器操作的接口
  5. javax.transaction.xa.Xid:事务 XID 接口

事务管理器提供者:实现 UserTranssaction、TransactionManager、Transaction、TransactionSynchronizationRegistry、Synchronization、XID 接口,通过与 XAResource 接口交互来实现分布式事务

资源管理器提供者:XAResource 接口需要由资源管理器实现,该接口中定义了一些方法,这些方法会被事务管理器调用

  1. start 方法:开启事务分支,对应 XA 底层实现是 XA START
  2. end 方法:结束事务分支,对应 XA 底层实现是 XA END
  3. prepare 方法:准备提交分支事务,对应 XA 底层实现是 XA PREPARE
  4. commit 方法:提交分支事务,对应 XA 底层实现是 XA COMMIT
  5. rollback 方法:回滚分支事务,对应 XA 底层实现是 XA ROLLBACK
  6. recover 方法:列出所有处于 PREPARED 状态的事务分支,对应 XA 底层实现是 XA RECOVER

4.XA 二阶段提交

一阶段:执行 XA PREPARE 语句。事务管理器通知各个资源管理器准备提交它们的事务分支。资源管理器受到通知后执行 XA PREPARE 语句

二阶段:执行 XA COMMIT/ROLLBACK 语句。事务管理器根据各个资源管理器的 XA PREPARE 语句执行结果,决定是提交事务还是回滚事务。如果所有的资源管理器都预提交成功,那么事务管理器通知所有的资源管理器执行 XA 提交操作;如果有资源管理器的 XA PREPARE 语句执行失败,则由事务管理器通知所有资源管理器执行 XA 回滚操作

二、MySQL 对 XA 规范的支持

MySQL 从 5.0.3 版本开始支持 XA 分布式事务,且只有 InnoDB 存储引擎支持。MySQL Connector/J 从 5.0.0 版本开始直接提供对 XA 的支持。需要注意的是,在 DTP 模型中,MySQL 属于资源管理器,而一个完整的分布式事务中一般会存在多个资源管理器,由事务管理器来统一协调。因此,这里所说的 MySQL 对 XA 分布式事务的支持,一般指的是单台 MySQL 实例如何执行自己的事务分支

1.MySQL XA 事务的语法

  1. XA {START|BEGIN} xid [JOIN|RESUME]:开启 XA 事务,注意如果使用的是 XA START,那么不支持 [JOIN|RESUME] 语句
  2. XA END xid [SUSPEND [FOR MIGRATE]]:结束一个 XA 事务,不支持 [SUSPEND [FOR MIGRATE]] 语句
  3. XA PREPARE xid:准备提交 XA 事务(如果使用了一阶段提交,该过程可以省略)
  4. XA COMMIT xid [ONE PHASE]:提交 XA 事务
  5. XA ROLLBACK xid:回滚 XA 事务
  6. XA RECOVER [CONVERT XID]:列出所有处于 Prepare 阶段的 XA 事务

2.MySQL XID 详解

在 MySQL 的事务语法中的最后都会跟上 XID,MySQL 作为事务分支标识符是在 XA 规范中定义的。XID 的结构描述如下:

#define XIDDATASIZE 128
#define MAXGTRIDSSIZE 64
#define MAXBQUALSIZE 64
struct xid_t {
	long formatID;
	long gtrid_length;
	long bqual_length;
	char data[XIDDATASIZE];
};
typedef struct xid_t XID;
extern int ax_reg(int, XID *, long);
extern int ax_unreg(int, long);

我们可以看到,在 XID 中有 4 个字段,下面分别解释各字段的含义:

  1. formatID:记录 gtrid、bqual 的格式,类似 Memcached 中 flags 字段的作用。XA 规范中通过一个结构体约定了 XID 的组成部分,但没有规定 data 中存储的 gtrid、bqual 的内容应该是什么格式
  2. gtrid_length:全局事务标识符(Global Transaction Identifier),最大不能超过 64 字节
  3. bequal_length:分支限定符(Branch Qualifier),最大不能超过 64 字节
  4. data:XID 的值,即 gtrid 和 bqual 拼接后的内容。在 XID 的结构体中,没有 gtrid 和 bqual,只有 gtrid_length、bqual_length。由于二者的内容都存储在 data 中,因此我们可以根据 data 反推出 gtrid 和 bqual。举例来说,假设 gtrid 为 abc,bqual 为 def,那么 gtrid_length = 3,bqual_length = 3,data = abcdef。反推的时候,从 data[0] 到 data[gtrid_length - 1] 之间的部分就是 gtrid 的值,从 data[gtrid_length] 到 data[gtrid_length + bqual_length - 1] 部分就是 bqual 的值

3.MySQL XA 事务的状态

MySQL XA 事务状态是正确执行 XA 事务的关键。每次执行 MySQL 的 XA 事务语句都会修改 XA 事务的状态,进而执行不同的 XA 语句。XA 事务状态流程如下图所示:

在这里插入图片描述

  • 在 XA START 和 XA END 之间执行的是业务 SQL 语句,无论是否执行成功, 都应该执行 XA END
  • 在 IDLE 状态下的事务可以直接执行 XA COMMIT,这里我们可以这样理解,当只有一个资源管理器的时候,可以直接退化成一阶段提交
  • 只有状态为 Failed 的时候,才能执行 XA ROLLBACK 进行 XA 事务回滚
  • XA 事务和非 XA 事务(即本地事务)是互斥的。例如,已经执行了 XA START 命令来开启一个 XA 事务,则本地事务不会被启动,直到 XA 事务被提交或回滚为止。相反的,如果已经使用 START TRANSACTION 启动了一个本地事务,则 XA 语句不能被使用,直到该事务被提交或回滚为止

4.MySQL XA 的问题

MySQL 低于 5.7 版本会出现的问题

  1. 已经预提交的事务,在客户端退出或者服务宕机的时候,二阶段提交的事务会被回滚
  2. 在服务器故障重启提交后,相应的 BinLog 会丢失

MySQL 5.6 版本在客户端退出的时候,会自动回滚已经准备好的事务,这是因为,对于处于 Prepare 状态的事务,MySQL 是不会记录 BinLog 的(官方解释为减少 fsync,起到优化的作用),Prepare 状态以前的操作信息都保存在连接的 IO_CACHE 中,如果此时客户端退出了,那么 BinLog 信息会被丢弃,重启后会丢失数据

MySQL 高版本的优化

事务在 Prepare 阶段就完成了写 BinLog 的操作(通过新增一种名为 XA_prepare_log_event 的 event 类型来实现)

三、XA 规范的问题思考

XA 二阶段规范虽然提供了分布式事务的解决思路与方案,但是自身也存在很多问题

1.XA 规范的缺陷

下面使用两个 MySQL 实例,完成一次 XA 分布式事务,如下图所示:

在这里插入图片描述

XA 规范中每个分支事务的执行都是同步的,并且只会存在一个事务协调者,由于网络的不稳定性,可能会出现数据不一致的问题。总体来说,XA 分布式事务会存在如下几个问题

同步阻塞

全局事务内部包含多个独立的事务分支,这些事务分支要么都成功,要么都失败。各个事务分支的 ACID 特性共同构成了全局事务的 ACID 特性,即单个事务分支支持的 ACID 特性被提升到分布式事务的范畴。即使在非分布式事务中,如果对读操作很敏感,我们也需要将事务隔离级别设置为串行化。而分布式事务更是如此,可重复读隔离级别不足以保证分布式事务的一致性。如果我们使用 MySQL 来支持 XA 分布式事务,那么最好将事务隔离级别设置为串行化。串行化是 4 个事务隔离级别中最高的级别,也是执行效率最低的级别

单点故障

一旦协调者事务管理器发生故障,参与者资源管理器会一直阻塞下去。尤其在两阶段提交的第二个阶段,如果协调者发生故障,那么所有的参与者都将处于锁定事务资源的状态中,无法继续完成事务操作(如果是协调者宕机,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)

数据不一致

在 Commit 阶段,当协调者向参与者发送 commit 请求后,发生了局部网络异常或者在发送 commit 请求的过程中,协调者发生了故障,会导致只有一部份参与者接收到了 commit 请求。而这部分参与者接到 commit 请求之后就会执行 commit 操作,但是其他部分未接到 commit 请求的参与者无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象

2.解决 XA 数据不一致的问题

日志存储

记录 XA 事务在每个流程中的执行状态,是解决 XA 数据不一致问题的关键。至于日志应该存储在哪里,使用什么存储,则根据具体需求确定,一般推荐采用中心化的存储方式,比如数据库。下表是一个简单的事务日志的数据结构:

在这里插入图片描述

自定义事务回复

事务恢复,首先通过 XA recovery 命令从资源管理器中获取需要被恢复的事务记录,然后根据 XID 匹配应用程序中存储的日志,根据事务状态进行提交或回滚,大体流程如下图所示:

在这里插入图片描述

4.解决事务管理器的单点故障问题

解决事务管理器的单点故障问题,我们一般会想到集群部署和注册中心。实际上,注册中心检测服务是否可用也是需要时间的。目前业界大致有两种解决方式,一种是去中心化部署(事务管理器嵌套在业务系统中),一种是中心化部署,如下图所示:

在这里插入图片描述

  • 去中心化部署:事务管理器嵌套在应用程序里面,不再单独部署。集群模式中事务角色由应用程序来解决
  • 中心化部署:事务管理器单独部署,然后与应用程序进行远程通信。集群模式中事务角色依赖其自身解决

四、主流的解决方案

XA 规范虽已提出多年,但在开源社区中,完整的解决方案并不是很多,下面给大家简单介绍几个目前开源社区中主流的 XA 分布式事务解决方案

Atomikos 解决方案

Atomikos 由免费的社区版本和收费的商业版本

  • 官网地址:https://www.atomikos.com
  • 社区版源码地址:https://github.com/atomikos/transactions-essentials
  • 社区版与商业版对比:https://www.atomikos.com/Main/CompareSubscriptions?done_form=1

Hmily 解决方案

Hmily 是国内 Dromara 开源社区提供的一站式分布式事务解决方案

  • 官网地址:https://dromara.org
  • 项目源码地址:https://github.com/dromara/hmily

Narayana 解决方案

Narayana 是 Jboos 团队提供的 XA 分布式事务解决方案

  • 官网地址:http://narayana.io
  • 项目源码地址:https://github.com/jbosstm/narayana
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

313YPHU3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值