MySQL · 捉虫动态 · 连接断开导致XA事务丢失

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: 我们看到在MySQL 5.7版本里大量遗留很多年的bug都被fix掉了,bug#12161就是其中一个,该bug在2005年第一次report到Bug list上,十年之后终于在MySQL 5.7.7 第一个RC版本被fix了。 Bug描述 当我们显式开启一个XA事务,执行操作,并完成XA PR

我们看到在MySQL 5.7版本里大量遗留很多年的bug都被fix掉了,bug#12161就是其中一个,该bug在2005年第一次report到Bug list上,十年之后终于在MySQL 5.7.7 第一个RC版本被fix了。

Bug描述

当我们显式开启一个XA事务,执行操作,并完成XA PREPARE后,如果Kill session或者主动断开再重连执行XA RECOVER,之前的这个XA事务就会直接丢失掉了。

例如:

mysql> XA BEGIN 'abc';
Query OK, 0 rows affected (0.00 sec)
   
mysql> INSERT INTO t1 VALUES (1,2,3);
Query OK, 1 row affected (0.00 sec)
   
mysql> XA END 'abc';
Query OK, 0 rows affected (0.00 sec)
   
mysql> XA PREPARE 'abc';
Query OK, 0 rows affected (0.00 sec)
   
mysql> Ctrl-C -- exit!
Aborted
   
mysql> XA RECOVER;
Empty set (0.00 sec)

有趣的是,如果在XA PREPARE后把实例KILL掉,是可以通过XA RECOVER恢复的:

mysql> XA RECOVER;
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
| 1 | 3 | 0 | abc |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)
   
mysql> XA COMMIT 'abc';
Query OK, 0 rows affected (0.00 sec)

虽然实例异常重启可以恢复事务,但引入的另外一个问题是:事务变更的binlog丢失,导致主备数据不一致。

bug产生的原因也很简单:在退出session时,线程总是会去无条件的回滚掉自己尚未提交的事务。

官方修复

持久化

为了解决这个问题,将XA的两阶段记录到了Binlog中;

对于上文描述的序列,当执行到XA PREPARE时,记录第一阶段的binlog,如下:

Query event : XA START X'616263',X'’,1  // 这里的'616262'即是'abc'的十六进制编码
Table_map event
Write_rows event
Query event:XA END X'616263',X'',1
XA_prepare event: XA PREPARE X'616263',X'’,1

这时候该XA事务同时在InnoDB层(事务处于Prepare状态,Redo持久化到磁盘)和Server层都有持久化信息。

其中XA_PREPARE事件是新引入的事件类型(内部类为XA_prepare_event),以后版本升级需要注意到这个低版本不兼容事件。

然后再执行XA COMMIT ‘abc’,产生新的事件:

Query event:XA COMMIT X'616263',X'',1

如果执行XA ROLLBACK,则记录:

Query event:XA ROLLBACK X'616263',X'',1

由于XA PREPARE和XA COMMIT是分开执行的,因此在这两个事件中间可能存在别的事务,备库复制线程需要处理这种情况。

为了实现XA PREPARE写binlog,对binlog_prepare进行了扩展,这里会调用mysql_bin_log.commit, 将cache中的binlog刷到文件中。

Tips:XID可以包含三个部分:gtrid, [, bqual [, format ID]],其中gtrid是必选的,表示全局标识,bqual是分支标识,默认为空’‘,format ID是一个unsigned整型,默认值为1,在上例中,我们只指定了gtrid为’abc’,因此bqual段和format ID均为默认值。更具体的描述参考官方文档

如何恢复

当会话断开时(例如kill session或者一次干净的shutdown/restart操作),我们必须要能恢复该事务,之前的逻辑是在cleanup时,直接回滚所有的活跃事务。在新版本中,对XA PREPARE的事务做了特殊处理(THD::cleanup),如果处于Prepare状态,就将事务的in_recovery设置为TRUE,并更新到hash表transaction_cache中(transaction_cache_detach),该hash表用于维护所有XA事务。

对于非XA的活跃事务,在会话断开时,依然采用回滚策略。

当重连客户端后,我们可以直接执行 XA COMMIT ‘abc’,这时候会通过XID关键字去搜索transaction_cache并将对应的事务提交掉。

同时BINLOG的状态要保持一致,如果会话断开前的XA PREPARE没有记录Binlog, 重连后执行XA COMMIT也不应该记录。

备库复制

由于XA PREPARE和XA COMMIT是分开记录的,当碰到XA COMMIT时,备库采用等待之前的事务全部完成,然后再执行的方式(相当于退化到串行)。

另外,我们知道在一个正常的会话过程中,总是为其cache一个事务对象,新的事务会重用这个事务对象,避免多次分配;而XA事务的COMMIT和PREPARE是分离的,需要为XA事务单独分配事务对象。因此复制线程执行XA START时,将其拥有的事务对象临时保存起来(detach_native_trx),当执行到XA_prepare_log_event事件时,再将其恢复给复制线程,同时XA事务对象关闭read view,将is_recovered设置为TRUE(函数innodb_replace_trx_in_thd)。

随后复制线程在执行到XA COMMIT时直接根据XID找到对应的XA事务进行提交。

参考:

WL#6860 Binlogging XA-prepared transaction
Github:git show f4c37f7aea732763947980600c6882ec908a54a0
MySQL 5.7.7-RC

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
23天前
|
关系型数据库 MySQL 数据库连接
Unity连接Mysql数据库 增 删 改 查
在 Unity 中连接 MySQL 数据库,需使用 MySQL Connector/NET 作为数据库连接驱动,通过提供服务器地址、端口、用户名和密码等信息建立 TCP/IP 连接。代码示例展示了如何创建连接对象并执行增删改查操作,确保数据交互的实现。测试代码中,通过 `MySqlConnection` 类连接数据库,并使用 `MySqlCommand` 执行 SQL 语句,实现数据的查询、插入、删除和更新功能。
|
17天前
|
存储 缓存 关系型数据库
MySQL底层概述—9.ACID与事务
本文介绍了数据库事务的ACID特性(原子性、一致性、隔离性、持久性),以及事务控制的演进过程,包括排队、排它锁、读写锁和MVCC(多版本并发控制)。文章详细解释了每个特性的含义及其在MySQL中的实现方式,并探讨了事务隔离级别的类型及其实现机制。重点内容包括:ACID特性(原子性、持久性、隔离性和一致性的定义及其实现方式)、事务控制演进(从简单的全局排队到复杂的MVCC,逐步提升并发性能)、MVCC机制(通过undo log多版本链和Read View实现高效并发控制)、事务隔离级别(析了四种隔离级别(读未提交、读已提交、可重复读、可串行化)的特点及适用场景)、隔离级别与锁的关系。
|
2月前
|
关系型数据库 MySQL 数据库连接
数据库连接工具连接mysql提示:“Host ‘172.23.0.1‘ is not allowed to connect to this MySQL server“
docker-compose部署mysql8服务后,连接时提示不允许连接问题解决
|
16天前
|
关系型数据库 MySQL 网络安全
如何排查和解决PHP连接数据库MYSQL失败写锁的问题
通过本文的介绍,您可以系统地了解如何排查和解决PHP连接MySQL数据库失败及写锁问题。通过检查配置、确保服务启动、调整防火墙设置和用户权限,以及识别和解决长时间运行的事务和死锁问题,可以有效地保障应用的稳定运行。
86 25
|
2月前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
103 7
MySQL事务日志-Undo Log工作原理分析
|
3月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
3月前
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(04)事务隔离级别、AICD、CAP、BASE原则一直搞不懂? | 看这篇就够了
本文详细介绍了数据库事务的四大特性(AICD原则),包括原子性、隔离性、一致性和持久性,并深入探讨了事务并发问题与隔离级别。同时,文章还讲解了分布式系统中的CAP理论及其不可能三角关系,以及BASE原则在分布式系统设计中的应用。通过具体案例和图解,帮助读者理解事务处理的核心概念和最佳实践,为应对相关技术面试提供了全面的知识准备。
|
5月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
165 43
|
4月前
|
关系型数据库 MySQL 网络安全
DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)
“Access denied for user ''@'ip' (using password: YES)”错误通常与MySQL用户权限配置或网络设置有关。通过检查并正确配置用户名和密码、用户权限、MySQL配置文件及防火墙设置,可以有效解决此问题。希望本文能帮助您成功连接MySQL数据库。
390 4
|
4月前
|
关系型数据库 MySQL
mysql事务特性
原子性:一个事务内的操作统一成功或失败 一致性:事务前后的数据总量不变 隔离性:事务与事务之间相互不影响 持久性:事务一旦提交发生的改变不可逆

相关产品

  • 云数据库 RDS MySQL 版