破产码农

IT圈最会讲故事的网红 · 南山彭于晏

最近在生产上变更时遇到从机死锁的问题。表现的现象为:同一张的表的DROP TABLE操作进入了同一组。而由于并行复制,并且从机提交顺序需要保证与主机一致,因此产生了死锁。

从上图可以看到SQL语句DROP TABLE IF EXISTS z对应的二进制日志中的last_committed值都为3,也就是他们处于同一组。

若这时发生Worker Thread 2先执行,且要求从机提交顺序与主机一致,那么Worker Thread 2提交前会一直等待Worker Thread 1完成,而由于Worker Thread 2已经执行了DROP TABLE操作,Worker Thread 1无法获得元数据锁去执行删除同样的表z,因此产生经典的AB-BA死锁。

现在要解决这个问题,主要是思考:为什么DROP TABLE IF EXISTS z会进入了同一组提交队列中。

可以肯定的是,这的的确确是一个显而易见的Bug。而由于之前对组提交代码相对比较熟悉,个人第一时间的反应这应该不是组提交那块代码的Bug。

后来同事反馈是由于使用gh-osc进行表结构变更时,工具会执行类似执行LOCK TABLES t WRITE,z WRITE多表锁定语句,从而引起死锁。

在有了上述线索后,就比较好定位死锁问题了。

死锁问题分析与定位

执行命令LOCK TABLES t WRITE,z WRITE会对表t、表z加上表级别的SHARED_NO_READ_WRITE的元数据锁。

这个元数据锁是在SQL引擎层的,对应源代码mdl.cc,并不是InnoDB引擎层的行记录锁。

接着,尝试测试在执行完上述SQL命令后,接着去执行DRO TABLE IF EXISTS z,这时发现对应表z上的表级别元数据锁已释放。

这也符合预期,毕竟删除表z,同时释放已持有的元数据锁,这是正常逻辑。

然而,在深入分析源码后,发现使用LOCK TABLES命令先去锁表,再去删除表,和普通的删除表操作,两者在释放元数据锁的时间是不一样的。

先来看普通的DROP TABLE操作,其内部的流程如下图所示:

正常的删除操作在完整提交后,才释放元数据锁。

但若通过命令LOCK TABLES现在去锁住两张表,接着再删除其中一张表,如我们演示的表z,则内部的流程如下图所示:

这时会发生在完整提交前就释放了表z的元数据锁。若这时有其他线程执行DROP TABLE IF EXISTS z的操作,则有可能进入到orderd_committed流程,从而导致两个DROP TABLE在同一提交组的可能。

若想要在自己的测试环境中更为容易的模拟出DROP TABLE在同提交一组的环境,同学们可以调整如下参数,:

binlog_group_commit_sync_delay = 1000000

binlog_group_commit_sync_no_delay_count = 8

若是源码调试,可以定位文件sql_table.cc,定位到函数mysql_rm_table设置断点。

内核层Bug修复方案

发现这个Bug后,姜老师花时间研究看了下源码。其实从代码逻辑上看是没有问题的,只是在从机回放的时候存在问题。所以,从严格意义上看,这个并不算Bug。只能说是一种不完美的缺陷。

然而,对于业务来说,这是的的确确的Bug。从机死锁,主从延迟,会导致各种严重的问题。

若将参数slave_preserve_commit_order设置为0,即不要求主从二进制日志顺序一致,可以规避上述问题,主从数据依然保证一致。但这不是完美的解决方案。

这个Bug的修复还真有些棘手,尝试想了很多方法,总没有特别好的思路。

例如参考之前DROP USER IF EXISTS,如果没有实际表删除,则不记录二进制日志。然而,这个方法并不好,官方最近版本DROP USER IF EXISTS无论是否有删除用户操作,也都记录二进制日志。

同样,若将上述thd->mdl_context.release_all_locks_for_name这行注释掉,那么会存在DROP TABLE z后,表z的元数据锁依然存在,只有当执行完命令UNLOCK TABLES才完全释放元数据锁。

这种方式,虽能避免上述问题,但还是有些实现上的不完美。

神奇的MySQL 8.0

这时看了下MySQL 8.0的源码mdl.cc,发现相对5.7做了比较大的重构。扫了下代码,无意中发现多了一种新类型的元数据锁——TABLESPACE元数据锁。

接着测试验证发现8.0并不存在5.7上述的Bug!!!因为DROP TABLE IF EXISTS只释放TABLE元数据锁,并不释放TABLESPACE元数据锁。

那么当线程2执行同样命令时,则由于TABLESPACE元数据存在,会触发等待,因此也不存在同一组中存在相同的DDL。

至于为什么要引入TABLESAPCE的元数据锁,可看官方的Worklog:https://dev.mysql.com/worklog/task/?id=7957

复盘与思考

从数据库角度看,这并不是MySQL内核层的死锁Bug。

这是因为使用gh-osc工具,引发的从机并行复制潜在的Bug。从概率上看也并不一定100%可以复现。

在翻看gh-osc工具源码中,也发现已经有用户提出从机死锁问题。官方也计划在1.1版本中修复。主要是让已经删除的表,不再有多次删除的可能。

当然,非要说是内核Bug,其实也是。毕竟二进制日志中last_committed值是错误的,从而引发从机并行回放的死锁。

这个Bug并不好很直观的进行修复。不过在8.0中,由于引入了TABLESAPCE元数据锁,反而弯打正着地解决了这个Bug。

好在这个Bug并非致命,发生概率非常小。若不使用gh-osc,则99%的概率不会遇到。若你有遇到,不妨留言,看看同学们是怎么解决这个的呢?

-----------------------

公众号:破产码农(ID:manongBR)

B站:Jiang老师

微博:破产码农

知乎:破产码农

mysql元数据死锁日志_这个未修复的MySQL 5.7死锁Bug,你知道么?相关推荐

  1. mysql 删除过期日志_【转】对mysql日志进行操作的总结包括 启用,过期自动删除 等...

    近段时间一直在研究mysql的日志系统,在网上看了N多mysql日志操作的文章,但都过于零乱,为了让自己以后不再搞忘,特作出以下总结: 1. 以前我错误的认为mysql的日志可以恢复到任何时间的状态, ...

  2. c语言连接数据库例子,c语言操作mysql数据库小例子_互帮互助(C language MySQL database operation example _ mutual help).doc...

    这是精心收集的精品经典资料,值得下载保存阅读! c语言操作mysql数据库小例子_互帮互助(C language MySQL database operation example _ mutual h ...

  3. mysql数据库binlog日志截断报错,导致mysql主从同步失败故障排查

    mysql数据库binlog日志截断报错,导致mysql主从同步失败故障排查 Got fatal error 1236 from master when reading data from binar ...

  4. 查看mysql数据库的死锁日志_【MySQL】mysql死锁以及死锁日志分析

    1.死锁的概念 死锁:死锁一般是事务相互等待对方资源,最后形成环路造成的. 对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行. 发生死锁会返回ERROR:1213 错误提示,大部分的死 ...

  5. mysql排插问题_手把手教你分析 MySQL 死锁问题

    原标题:手把手教你分析 MySQL 死锁问题 前言 前几天跟一位朋友分析了一个死锁问题,所以有了这篇图文详细的博文,哈哈~ 发生死锁了,如何排查和解决呢?本文将跟你一起探讨这个问题 准备好数据环境 模 ...

  6. mysql数据库崩溃日志_我们崩溃并丢失了所有基本数据日志。 我们哪里错了?

    mysql数据库崩溃日志 放松,没有人迷失森林. 他们失去的是大量必要的数据日志. 此处的主题公司称为TheCompany. 发现问题的开发人员是Bob. 在本文中,我想讨论软件开发中的人为错误以及针 ...

  7. 如何linux查看mysql目录下日志_测试人员如何在linux服务器中查询mysql日志?

    测试工程师在测试软件的过程中,流程往往是先接口测试,接着就是功能性测试.在做功能性测试的时候,往往有这么一个工作场景,就是出现错误后,我们怎么快速排除数据库报错. 举例某个电商网站,当我们文本框中输入 ...

  8. mysql grep 提取错误日志_详解grep获取MySQL错误日志信息的方法

    为方便维护MySQL,写了个脚本用以提供收集错误信息的接口.这些错误信息来自与MySQL错误日志,而 通过grep mysql可以获取error-log的路径. 以下是全部相关代码: #!/usr/b ...

  9. mysql 刷新二进制日志_使用binlog日志恢复MySQL数据库删除数据的方法

    binlog日志简介: binlog 就是binary log,二进制日志文件,这个文件记录了MySQL所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间. b ...

最新文章

  1. Algs4-1.1.13编写一段代码,打印出一个M行N列的二维数组的转置(交换行和列)
  2. Java 线程池中的线程复用是如何实现的?
  3. ASP.NET MVC中使用AJAX(XMLHttpRequest、Microsoft AJAX Library......)
  4. 【物联网】 ESP8266 Ubuntu开发环境的搭建
  5. MySQL主从复制虽好,能完美解决数据库单点问题吗?
  6. Android 升级到android studio 2.2项目死活run不起来
  7. 指数级暴增、复杂场景下,揭秘百度云原生湖仓架构等系列数据产品
  8. XSD(XML Schema Definition)学习笔记
  9. 华大基因辟谣“基因编辑58个婴儿”;苹果发布头戴式耳机AirPods Max;Debian 10.7发布|极客头条...
  10. Hbase数据结构+hbase shell基本语法
  11. 小学计算机应用到英语课教案,信息技术在小学英语教学中的应用
  12. 2021年下半年软考真题软件设计师真题答案(上午题)
  13. 手机连接USB通过宽带免费上网
  14. 1946年第一台公认电子计算机,1946年诞生的世界上公认的第一台电子计算机是()。...
  15. 解决Chrome浏览器主页被篡改(劫持)hh899899.com的问题
  16. at命令不生效 linux_linux中at命令详解
  17. echarts学习笔记
  18. 专家 | 黄道丽:网络安全漏洞披露规则及其体系设计
  19. X230网卡驱动安装总不成功的问题
  20. kotlin混淆后mapping定位

热门文章

  1. Redis大集群扩容性能优化实践
  2. 36张图详解网络基础知识
  3. 1.5w字,30图带你彻底掌握 AQS!
  4. JAVA 线上故障排查指南!
  5. 如何让你的Nginx 提升10倍性能?
  6. 优秀员工应该具备的11个特质
  7. 分享13个Spring Boot 优质开源项目!商城,ERP,管理系统
  8. android 自定义命名空间,Android自定义ActionBar实例
  9. 如何开好一个 OKR 评审会议?
  10. Pytorch——YOLOv3