详解 Mysql 分布式事务 XA(跨数据库事务)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 详解 Mysql 分布式事务 XA(跨数据库事务)

在开发中,为了降低单点压力,通常会根据业务情况进行分表分库,将表分布在不同的库中(库可能分布在不同的机器上)。在这种场景下,事务的提交会变得相对复杂,因为多个节点(库)的存在,可能存在部分节点提交失败的情况,即事务的 ACID 特性需要在各个不同的数据库实例中保证。比如更新 db1 库的 A 表时,必须同步更新 db2 库的 B 表,两个更新形成一个事务,要么都成功,要么都失败。

 

那么我们如何利用 mysql 实现分布式数据库的事务呢?

Mysql 为我们提供了分布式事务解决方案(https://dev.mysql.com/doc/refman/5.7/en/xa.html 这是 mysql5.7 的文档)

这里先声明两个概念:

资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。数据库就是一种资源管理器。资源管理还应该具有管理事务提交或回滚的能力。

事务管理器(transaction manager):事务管理器是分布式事务的核心管理者。事务管理器与每个资源管理器(resource manager)进行通信,协调并完成事务的处理。事务的各个分支由唯一命名进行标识。

mysql 在执行分布式事务(外部 XA)的时候,mysql 服务器相当于 xa 事务资源管理器,与 mysql 链接的客户端相当于事务管理器。

 

分布式事务原理:分段式提交

分布式事务通常采用 2PC 协议,全称 Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过 2PC 协议将提交分成两个阶段:

  1. prepare;
  2. commit/rollback;

阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者 ready 时,向 transaction manager 报告已准备就绪。

阶段二为提交阶段(commit)。当 transaction manager 确认所有参与者都 ready 后,向所有参与者发送 commit 命令。

如下图所示:

事务协调者 transaction manager

因为 XA 事务是基于两阶段提交协议的,所以需要有一个事务协调者(transaction manager)来保证所有的事务参与者都完成了准备工作 (第一阶段)。如果事务协调者(transaction manager)收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。MySQL 在这个 XA 事务中扮演的是参与者的角色,而不是事务协调者(transaction manager)。

 

Mysql 的 XA 事务分为外部 XA 和内部 XA

外部 XA 用于跨多 MySQL 实例的分布式事务,需要应用层作为协调者,通俗的说就是比如我们在 PHP 中写代码,那么 PHP 书写的逻辑就是协调者。应用层负责决定提交还是回滚,崩溃时的悬挂事务。MySQL 数据库外部 XA 可以用在分布式数据库代理层,实现对 MySQL 数据库的分布式事务支持,例如开源的代理工具:网易的 DDB,淘宝的 TDDL 等等。

内部 XA 事务用于同一实例下跨多引擎事务,由 Binlog 作为协调者,比如在一个存储引擎提交时,需要将提交信息写入二进制日志,这就是一个分布式内部 XA 事务,只不过二进制日志的参与者是 MySQL 本身。Binlog 作为内部 XA 的协调者,在 binlog 中出现的内部 xid,在 crash recover 时,由 binlog 负责提交。(这是因为,binlog 不进行 prepare,只进行 commit,因此在 binlog 中出现的内部 xid,一定能够保证其在底层各存储引擎中已经完成 prepare)。

MySQL XA 事务基本语法

XA {START|BEGIN} xid [JOIN|RESUME] 启动 xid 事务 (xid 必须是一个唯一值;不支持 [JOIN|RESUME] 子句)

XA END xid [SUSPEND [FOR MIGRATE]] 结束 xid 事务 ( 不支持 [SUSPEND [FOR MIGRATE]] 子句)

XA PREPARE xid 准备、预提交 xid 事务

XA COMMIT xid [ONE PHASE] 提交 xid 事务

XA ROLLBACK xid 回滚 xid 事务

XA RECOVER 查看处于 PREPARE 阶段的所有事务

 

PHP 调用 MYSQL XA 事务示例

1、首先要确保 mysql 开启 XA 事务支持

SHOW VARIABLES LIKE '%xa%'

如果 innodb_support_xa 的值是 ON 就说明 mysql 已经开启对 XA 事务的支持了。如果不是就执行:

SET innodb_support_xa = ON

2、代码如下:

<?PHP
$dbtest1 = new mysqli("172.20.101.17","public","public","dbtest1")or die("dbtest1 连接失败");
$dbtest2     = new mysqli("172.20.101.18","public","public","dbtest2")or die("dbtest2 连接失败");
//为XA事务指定一个id,xid 必须是一个唯一值。
$xid = uniqid("");
//两个库指定同一个事务id,表明这两个库的操作处于同一事务中
$dbtest1->query("XA START '$xid'");//准备事务1
$dbtest2->query("XA START '$xid'");//准备事务2
try {
    //$dbtest1
    $return = $dbtest1->query("UPDATE member SET name='唐大麦' WHERE id=1") ;
    if($return == false) {
       throw new Exception("库dbtest1@172.20.101.17执行update member操作失败!");
    }
    //$dbtest2
    $return = $dbtest2->query("UPDATE memberpoints SET point=point+10 WHERE memberid=1") ;
    if($return == false) {
       throw new Exception("库dbtest1@172.20.101.18执行update memberpoints操作失败!");
    }
    //阶段1:$dbtest1提交准备就绪
    $dbtest1->query("XA END '$xid'");
    $dbtest1->query("XA PREPARE '$xid'");
    //阶段1:$dbtest2提交准备就绪
    $dbtest2->query("XA END '$xid'");
    $dbtest2->query("XA PREPARE '$xid'");
    //阶段2:提交两个库
    $dbtest1->query("XA COMMIT '$xid'");
    $dbtest2->query("XA COMMIT '$xid'");
} 
catch (Exception $e) {
    //阶段2:回滚
    $dbtest1->query("XA ROLLBACK '$xid'");
    $dbtest2->query("XA ROLLBACK '$xid'");
    die($e->getMessage());
}
$dbtest1->close();
$dbtest2->close();
?>

XA 的性能问题

XA 的性能很低。一个数据库的事务和多个数据库间的 XA 事务性能对比可发现,性能差 10 倍左右。因此要尽量避免 XA 事务,例如可以将数据写入本地,用高性能的消息系统分发数据。或使用数据库复制等技术。只有在这些都无法实现,且性能不是瓶颈时才应该使用 XA。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
30天前
|
SQL 关系型数据库 MySQL
乐观锁在分布式数据库中如何与事务隔离级别结合使用
乐观锁在分布式数据库中如何与事务隔离级别结合使用
|
26天前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
97 43
|
10天前
|
关系型数据库 分布式数据库 数据库
PostgreSQL+Citus分布式数据库
PostgreSQL+Citus分布式数据库
42 15
|
8天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
23 1
|
10天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
25 4
|
16天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
83 1
|
19天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
61 2
|
22天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
89 4
|
4天前
|
运维 关系型数据库 MySQL
安装MySQL8数据库
本文介绍了MySQL的不同版本及其特点,并详细描述了如何通过Yum源安装MySQL 8.4社区版,包括配置Yum源、安装MySQL、启动服务、设置开机自启动、修改root用户密码以及设置远程登录等步骤。最后还提供了测试连接的方法。适用于初学者和运维人员。
34 0
|
27天前
|
存储 关系型数据库 MySQL
如何在MySQL中创建数据库?
【10月更文挑战第16天】如何在MySQL中创建数据库?