TDSQL中修复的mysql内核bug

在TDSQL这两年多的开发工作中,我感觉很自豪的一件事是我修复了不少mysql-5.7.17和mariadb-10.1.9的内核bug,这些bug大多已经报告给了MySQL/MariaDB官方开发团队,在每个bug描述中我会贴出来bug报告的连接。本文将大略介绍这些bug的概况,我在将来会写更多文章详细介绍每个bug的具体问题分析以及解决思路。本文列出的所有bug都已经修复,经过验证可以正确工作并解决相关问题。

这里先说一下为什么我要提交代码给mysql/mariadb官方开发团队,主要有一下几个好处:

1.官方开发者可以review我提交的patch,帮助完善patch,发现和解决之前可能没有想到的问题。我自己做mysql内核开发和bug修复时会跑mtr(mysql自带的测试包),确保所有测例通过,并且新增测例覆盖新增的功能和代码。不过即使如此,也可能有未考虑到的点,因此可以借助mysql/mariadb官方的力量。

2.将来在新版本合并代码会很容易,因为这些patch的改动已经在官方发布的新版本中了,就不需要再次合并了。

3.为开源软件做出贡献,这样的一种社区氛围长期来看对所有mysql用户都是好事。

下面就是每个bug的简介,主要介绍其症状和危害性。具体解决方法和分析过程以及修复代码patch请看bug链接的页面,我未来也会写文章做出更详细的讲解和分析。下文中经常提到的英文术语简介如下:

XA:分布式事务处理

DML: 数据操作语言,比如SQL语言中的INSERT,UPDATE,DELETE,SELECT等语句。

Mutex:互斥量,操作系统基础功能

安装插件流程中的mutex死锁

执行install plugin语句时,负责插件状态互斥的一个mutex与负责全局变量状态互斥的mutex可能发生死锁。死锁一旦发生,mysqld就hang住了,所有连接都无法继续工作。我提交给mysql官方开发团队的bug报告如下:

Bug?#88693Mutex deadlock causing mysqld to hang and cease to work

https://bugs.mysql.com/bug.php?id=88693

Optimize table与DML语句的冲突

当执行optimize table时由大量的DML语句(比如delete)在执行时,innodb有可能crash在一个assert中,导致mysqld进程崩溃退出。详情请见我的bug报告:

Bug #88511innodb assertion failure in table rename

https://bugs.mysql.com/bug.php?id=88511

percona备机复制在特定事件序列情况下卡住

对于mysql-5.7的XA事务来说,在一个XA事务的任何位置中断slave IO线程的连接后都会出问题,导致备机sql线程陷入死循环,备机复制无法继续下去。我提交给mysql官方开发团队的bug报告如下:

Bug #87385Partial external XA transactions are not rolled back correctly

https://bugs.mysql.com/bug.php?id=87385

MYSQL 客户端的AUTOCOMMIT状态位设置不准确

当global autocommit是时候 新开启一个mysql连接时,客户端返回的autocommit状态位是1,应该是0. mariadb和percona都有这个问题。这个bug对于绝大多数最终用户而言可能是无感知的,不过TDSQL的网关模块依赖于这个状态位来正确工作,因而我们发现并修复了这个bug。

我提交给mysql官方开发团队的bug报告如下:

Bug #87813Incorrect autocommit status bit in server_status at connection startup

https://bugs.mysql.com/bug.php?id=87813

无法在AUTOCOMMIT=0时结束PREPARED状态的XA事务

如果一个连接的autocommit=0,然后执行XA COMMIT/XA ROLLBACK来结束一个事务,那么Mysql会报错并拒绝操作。报错信息:

ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the NON-EXISTING state

这样导致PREPARED状态的XA事务在非autocommit设置下无法被提交或者回滚,分布式事务处理机制无法正确工作。

我提交给mysql官方开发团队的bug报告如下:

Bug #87836XA COMMIT/ROLLBACK rejected by non-autocommit session with no active transaction

https://bugs.mysql.com/bug.php?id=87836

percona XA事务提交和回滚的恢复机制

官方mysql-5.7的实现中,没有处理XA事务分支的binlog + engine恢复,包括XA PREPARE,XA COMMIT ... ONE PHASE以及XA COMMIT/XA ROLLBACK提交的事务的恢复,mysql-5.7都没有实现binlog事务恢复机制,因而在各种灾难情况下会发生丢失XA事务,数据不一致等致命问题。这些bug我们在TDSQL中都已经修复了。

这是一个巨大的开发任务,新增代码几千行,我提交给mysql官方开发团队的两个bug报告如下:

Bug #87560XA PREPARE log order error in replication and binlog recovery

https://bugs.mysql.com/bug.php?id=87560

Bug #84297Engine prepare executed after flush stage

https://bugs.mysql.com/bug.php?id=84297

Percona XA COMMIT/ROLLBACK事务的gtid管理

这类事件组(也就是一个xa事务的binlog的后半部分)在备机上面可能无法执行,因为主备切换的特殊时机下当前备曾是主机,已经执行过了。但是官方默认实现未考虑到这一点,就会导致备机可能无法连接到主机因为主机没有备机需要的gtid。此时的症状表现就是主备切换后,备机无法连上主机,产生反复连接和报错的循环,TDSQL在强同步模式下就无法运行了。这个bug已经修复,经过验证可以正确工作并解决相关问题。

Percona备机SQL线程执行XA_PREPARE_EVENT时,复制位置没有持久化

Percona备机SQL线程执行XA_PREPARE_EVENT时,复制位置没有持久化,于是备机crash然后重启之后,开始复制的位置就是错误的(会从更早的位置开始复制),就会导致复制卡住(比如要删除一个已经删除的行,或者更新时间找不到目标行,或者插入发生主键冲突)和数据不一致等严重问题。

我提交给mysql官方开发团队的bug报告如下:

Bug?#87389Replication position not persisted correctly for XA transactions

https://bugs.mysql.com/bug.php?id=87389

XA COMMIT事件没有被作为事务边界

MySQL-5.7的replication实现,依赖于一个事务状态分析对象,它根据扫描到的事件,维持一个当前事务状态,这个状态会被备机的复制机制使用。由于XA COMMIT这个事件没有被作为事务边界,就会导致很多XA相关的复制问题和bug。

我提交给mysql官方开发团队的bug报告如下:

Bug #87130XA COMMIT not taken as transaction boundary

https://bugs.mysql.com/bug.php?id=87130

XA PREPARE与xtrabackup不能协同工作

主要原因是mysql执行XA PREPARE语句期间没有获取COMMIT全局意向锁,导致它不能被xtrabackup阻塞住,就可能发生xtrabackup备份的数据丢失了prepared事务的严重问题,导致数据不一致。

我提交给mysql官方开发团队的bug报告如下:

Bug #84442XA PREPARE inconsistent with XTRABACKUP

https://bugs.mysql.com/bug.php?id=84442

XA COMMIT在其他连接中执行时与xtrabackup不能协同工作

如果XA COMMIT语句不是在当前XA事务所在的连接中执行的,而是当前连接断开后重新连接mysqld然后执行XA COMMIT,那么此时XA COMMIT不会获取全局COMMIT意向锁,也就不能被FTWRL阻挡住,于是就不能与xtrabackup正确地协同工作,导致数据不一致的严重问题。

我提交给mysql官方开发团队的bug报告如下:

Bug #84323XA-COMMIT may not be blocked by FTWRL

https://bugs.mysql.com/bug.php?id=84323

我们在做分布式事务的容灾测试期间,需要无数次反复kill掉和重启mysqld,偶尔会遇到mysqld无法启动的情况,报错就是 Another process with pid xxx is using unix socket file.

mariadb sleep时长不精确

这个是TDSQL的自研功能的bug修复。tdsql-mariadb-10.1.9中,我们为了使sleep()函数避免出现因为机器时间被调整而导致sleep()无法按时返回的问题,重新实现了sleep()函数.

修改后,tdsql-mariadb-10.1.9提供了两种sleep()函数的实现,第一种是我的新的实现方案,可以避免机器时间被调整而导致sleep()无法按时返回的问题,并且精度与官方实现相同,默认使用该方案;另外,可以通过动态设置全局变量use_tdsql_sleep_func=0,来使用mariadb官方的默认sleep()函数实现。

MariaDB InnoDB表空间文件头标志字段bug

这是我在MariaDB官网上面提交的bug报告:https://jira.MariaDB.org/browse/MDEV-9581

这个bug的症状是MariaDB-10.1.9无法使用MariaDB-10.0.10产生的数据目录:当指定datadir为这样一个目录时,mysqld进程在启动过程中发现错误而退出了。也就是说,如果你之前在使用MariaDB-10.0.x,有一个数据目录,里面有你珍贵的数据,然后现在你打算使用MariaDB-10.1.x,你会痛苦地发现,MariaDB-10.1.x无法用原来的数据目录启动,也就无法使用mysql_upgrade来升级数据目录。虽然可以使用dump/load的方法来规避问题,但是在数据量很大的情况下,这样做非常耗时,效率很低。这个bug已经修复,经过验证可以正确工作并解决相关问题。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180322G184JQ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券