MySQL Bug剖析之Slave节点并行复制死锁
此文已由作者温正湖授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
有天一早,DBA同学就找上来了,说有个DDB集群下的RDS实例Slave节点(从库)死锁了,请求支援。说实话,一大早就遇到死锁这种棘手的问题,我的内心是奔溃的。不过万幸的是,DBA说这个实例还未正式上线,处于上线前压测阶段。这么一来,至少现场可以一直保持着。方便定位问题。那么,是什么问题呢,不卖关子,直接上图:
这是show processlist的结果。可以看到有一大坨的连接,基本上都是权限操作相关的语句,全都卡在“waiting for table level lock”上。还有几个复制管理操作,比如stop slave,也卡住了。这密密麻麻一大堆,看得都烦。还是得从这些连接里面挖掘出少数有用的信息。所以登上实例的mysql客户端捋下才是王道。先看看有没有锁相关的直接信息:
show engine innodb status\G
------------
TRANSACTIONS
------------
Trx id counter 6506046
Purge done for trx's n:o < 6506038 undo n:o < 0 state: running but idle
History list length 2057
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421794207149728, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421794207150640, not started
里面根本就没有持锁相关的提示,而且事务全都处于not started状态。再看看InnoDB锁相关表:
mysql> select * from information_schema.INNODB_LOCK_WAITS;
Empty set (0.00 sec)
mysql>
mysql> select * from information_schema.INNODB_LOCKS;
Empty set (0.00 sec)
还是空空如也。既然这样,那直接看这些连接吧。理一理先后顺序,发现有3个连接是最早同时被卡主的:
| 284480 | system user | | dbn3 | Connect | 60771 | 0 | Waiting for table level lock | FLUSH PRIVILEGES |
| 28 | rdsadmin | localhost | NULL | Query | 60771 | 0 | Waiting for table level lock | select count(distinct(User)) from mysql.user where Super_priv = 'Y' |
| 284481 | system user | | dbn2 | Connect | 60771 | 0 | Waiting for preceding transaction to commit | GRANT SELECT ON *.* TO 'qs'@'10.122.170.%' IDENTIFIED WITH 'mysql_native_password' AS '*5B9E9DAAD2D1AD00E6D25C667B2E4EFD165CA560' |
有2个连接在等table lock,其中一个是用户连接,所做的事情是查询mysql.user表有super权限的账号,另一个连接,执行刷权限的操作。剩下的1个连接在等待前一个事务提交。其中第一个和第三个为system user。为了能够看到更具体的信息,我们进一步查询了performance_schema.threads表,得到如下结果:
mysql> select * from threads where THREAD_ID in (284481, 284480) order by PROCESSLIST_ID desc\G
*************************** 1. row ***************************
THREAD_ID: 284506
NAME: thread/sql/slave_worker
TYPE: FOREGROUND
PROCESSLIST_ID: 284481
PROCESSLIST_USER: rdsadmin
PROCESSLIST_HOST: localhost
PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Connect
PROCESSLIST_TIME: 62124
PROCESSLIST_STATE: Waiting for preceding transaction to commit
PROCESSLIST_INFO: GRANT SELECT ON *.* TO 'qs'@'10.122.170.%' IDENTIFIED WITH 'mysql_native_password' AS '*5B9E9DAAD2D1AD00E6D25C667B2E4EFD165CA560'
PARENT_THREAD_ID: 284504
ROLE: NULL
INSTRUMENTED: YES
HISTORY: YES
CONNECTION_TYPE: NULL
THREAD_OS_ID: 7281
*************************** 2. row ***************************
THREAD_ID: 284505
NAME: thread/sql/slave_worker
TYPE: FOREGROUND
PROCESSLIST_ID: 284480
PROCESSLIST_USER: rdsadmin
PROCESSLIST_HOST: localhost
PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Connect
PROCESSLIST_TIME: 62124
PROCESSLIST_STATE: Waiting for table level lock
PROCESSLIST_INFO: FLUSH PRIVILEGES
PARENT_THREAD_ID: 284504
ROLE: NULL
INSTRUMENTED: YES
HISTORY: YES
CONNECTION_TYPE: NULL
THREAD_OS_ID: 7280
2 rows in set (0.00 sec)
可以发现这两个system user连接其实是MySQL Multi-Threads(多线程,MTS,或并行)复制的worker线程,他们共同的父进程(PARENT_THREAD_ID)是284504。我们再看下这个父进程在干嘛:
mysql> select * from threads where THREAD_ID in (284504) order by PROCESSLIST_ID desc\G
*************************** 1. row ***************************
THREAD_ID: 284504
NAME: thread/sql/slave_sql
TYPE: FOREGROUND
PROCESSLIST_ID: 284479
PROCESSLIST_USER: rdsadmin
PROCESSLIST_HOST: localhost
PROCESSLIST_DB: NULL
PROCESSLIST_COMMAND: Connect
PROCESSLIST_TIME: 62124
PROCESSLIST_STATE: Waiting for dependent transaction to commit
PROCESSLIST_INFO: NULL
PARENT_THREAD_ID: 282714
ROLE: NULL
INSTRUMENTED: YES
HISTORY: YES
CONNECTION_TYPE: NULL
THREAD_OS_ID: 7279
1 rows in set (0.00 sec)
该父进程即为多线程复制的sql线程,其所处的状态为"Waiting for dependent transaction to commit",看代码可以发现,这个状态的意思是等待当前的Group提交后才能并行执行一下个Group的事务。我们知道InnoDB表是没有表锁的,而本例大量的连接在等表锁,根据其操作内容,可以基本确定是在等待mysql.user表的锁,该表是MyISAM表。grant to语句跟"FLUSH PRIVILEGES"语句肯定是互斥的。而flush语句状态为"Waiting for preceding transaction to commit",这状态的意思是等待同一个Group中靠前的事务先完成提交。那么它的前一个事务是什么呢?其实不好判断。
google一直是定位问题的好帮手,在分析这个案例的同时,也没忘去google一把,发现了一个有点类似的案例http://dbaplus.cn/news-11-1874-1.html。但我们的案例中并没有Flush tables with read lock。仅有的用户连接是"select count(distinct(User)) from mysql.user where Super_priv = 'Y' ",这个连接无法起到FTWRL的作用。那么会不会是"FLUSH PRIVILEGES"呢?其实有一定的可能性。但假若真是如此,那么就是MySQL本身的一个Bug了,因为没有用户连接的参与,2个mysqld自身的worker线程就导致了死锁。那么如何确定就是这个"FLUSH PRIVILEGES"阻塞了grant to呢。根据从库执行到的Master Binlog位置,看下对应的Binlog信息即可。查询到的结果如下:
从图中我们可以发现,last_commited同为734263的Group有2个事务,分别是"FLUSH PRIVILEGES"和" GRANT SELECT ON *.* TO 'qs'@'10.122.170.%' IDENTIFIED WITH 'mysql_native_password' AS '*5B9E9DAAD2D1AD00E6D25C667B2E4EFD165CA560'"。其中sequence_number为734264的"FLUSH PRIVILEGES"在前,sequence_number为734265的grant语句在后。在开启并行(或多线程)复制的从库上。734265语句先得到执行,到了commit阶段,由于设置了slave_preserve_commit_order参数,导致734265需要等待734264先提交后才能提交。但由于这两个事务都需要更新mysql.user,且该表为MyISAM表,加锁粒度为表级(table level),这就使得734265需要等待734264先提交后才能提交,但734264需要等待734265提交后才会释放的mysql.user表锁,于是last_commited为734263的这个Group的2个事务无法正常完成。进一步导致作为并行复制的事务分发线程的sql线程一直无法给worker线程派发下一个Group(last_commited为734265)的事务。这就把整个Slave的复制锁死了。
到这里,需要交代一个DBA提供的背景:"一开始是在ddb层,,去改用户密码,,来来回回改了几次,,,然后其中一个节点的内部从就出现了Waiting for table level lock ,,, 都是跟权限相关的"。我们结合Binlog信息可以进一步发现,上层至少在数据库dbn2、dbn3上分别同时执行了" GRANT SELECT ON *.* TO 'qs'@'10.122.170.%' IDENTIFIED WITH 'mysql_native_password' AS '*5B9E9DAAD2D1AD00E6D25C667B2E4EFD165CA560'"和"FLUSH PRIVILEGES"。由于这两个操作是都需要加mysql.user的表锁,所以实际执行时是互斥的,不存在并行提交的Group概念,或者说按照Group Commit机制,这两个操作是不会出现在同一个Group中的。
但为什么实际上却出现了呢,这是由于MySQL 5.7.3开始对group commit做了进一步优化,这里不做详细解释,感兴趣的同学可以看下这个参考文献(http://mysql.taobao.org/monthly/2016/08/01/)。
将该Bug上报给MySQL官方,得到了官方的开发同学的确认,并建了个bug(https://bugs.mysql.com/bug.php?id=89229)。该Bug对实际业务的影响很小,线上一般不会在多个数据库上并发执行赋权语句,而是由于是在从库上发生,即使出现了,也可以通过kill掉mysqld重新拉起解决该问题。此外,其实在执行" GRANT SELECT ON *.* TO 'qs'@'10.122.170.%' IDENTIFIED WITH 'mysql_native_password' AS '*5B9E9DAAD2D1AD00E6D25C667B2E4EFD165CA560'"后,并不需要执行"FLUSH PRIVILEGES"。grant to语句本身就会刷新权限信息。
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 当我们在谈论multidex65535时,我们在谈论什么
【推荐】 Vuex实践
【推荐】 机器学习、深度学习、和AI算法可以在网络安全中做什么?
MySQL Bug剖析之Slave节点并行复制死锁的更多相关文章
- MySQL 5.7 基于GTID主从复制+并行复制+半同步复制
环境准备 IP HOSTNAME SERVICE SYSTEM 192.168.131.129 mysql-master1 mysql CentOS7.6 192.168.131.130 mysql- ...
- mysql slave节点多线程复制
线上一个mysql主备延迟很大,master节点写入频繁,slave节点积累大量relay-log无法即使写入. 参考:https://www.cnblogs.com/conanwang/p/6006 ...
- 【MySQL】你以为设置了并行复制就降低延迟了?这个你绝对想不到!
在MySQL官方版本中,为了保证其的高可用性,一般情况我们会采用主从复制的方式来解决.当然,方法很多.而我们今天所要处理的是采用GTID方式并且开了多线程复制后,仍然延迟的情况,糟糕的是,延迟还在不断 ...
- 从MySQL 5.5到5.7看复制的演进
概要:MySQL 5.5 支持单线程模式复制,MySQL 5.6 支持库级别的并行复制,MySQL 5.7 支持事务级别并行复制.结合这个主线我们可以来分析一下MySQL以及社区发展的一个前因后果. ...
- Centos7.5部署MySQL5.7基于GTID主从复制+并行复制+半同步复制+读写分离(ProxySQL) 环境- 运维笔记 (完整版)
之前已经详细介绍了Mysql基于GTID主从复制的概念,原理和配置,下面整体记录下MySQL5.7基于GTID主从复制+并行复制+增强半同步复制+读写分离环境的实现过程,以便加深对mysql新特性GT ...
- MySQL5.7的组提交与并行复制
从MySQL5.5版本以后,开始引入并行复制的机制,是MySQL的一个非常重要的特性. MySQL5.6开始支持以schema为维度的并行复制,即如果binlog row event操作的是不同的sc ...
- MySQL5.7的并行复制
MySQL5.6开始支持以schema为维度的并行复制,即如果binlog row event操作的是不同的schema的对象,在确定没有DDL和foreign key依赖的情况下,就可以实现并行复制 ...
- MySQL并行复制(MTS)原理(完整版)
目录 MySQL 5.6并行复制架构 MySQL 5.7并行复制原理 Master 组提交(group commit) 支持并行复制的GTID slave LOGICAL_CLOCK(由order c ...
- 减少MySQL主从延迟的神器--并行复制大揭密
1. 简介 MySQL 5.6引入了基于schema的并行复制,即如果binlog events操作的是不同schema的对象,不是DDL,且操作的对象没有对其他schema的foreign key关 ...
随机推荐
- 错误 1 error C1083: 无法打开包括文件: “numpy/arrayobject.h”: No such file
问题:错误 1 error C1083: 无法打开包括文件: “numpy/arrayobject.h”: No such file 解答:加入include路径:E:\env\Anaconda2x6 ...
- Coding/Github/Bitbucket 地址
Coding:https://coding.net/u/OberonTony Github:https://github.com/Oberon-Tonya Bitbucket:https://bitb ...
- Spring LDAP
LDAP Spring LDAP 使用 - Sayi像秋天一样优雅 - 开源中国社区 http://docs.spring.io/spring-ldap/docs/current/reference/ ...
- #include <sys/socket.h>找不到头文件
ubuntu下socket编程涉及到头文件sys/socket.h 和sys/types.h.我是用的codeblocks编辑器,当我想查看socket,h头文件时编辑器提示找不到头文件. 我就想可能 ...
- ASP.NET MVC EXTJS 通用主菜单框架
一.说明 首先我不知道定义的文章标题是不是准确,我这篇博文介绍的是一个通用的软件主菜单框架,界面布局用的是extjs,还是先上一个图吧. 软件主界面左侧菜单采用的风格是extjs的手风琴模式,需要注意 ...
- Android 监听返回键退出程序的两种实现
1.Android 双击返回键退出程序 思路:用户按下返回键时设定一个定时器来监控是否2秒内实现了退出,如果用户没有接着按返回键,则清除第一次按返回键的效果,使程序还原到第一次按下返回键之前的状态.定 ...
- 将本地项目上传到git远程库(初始化)
准备条件: 首先,有一个远程仓库地址,本文中的地址为“http://git.xxxxxxxx.net.cn/jacun/imagegrap.git”; 第一步:在本地创建初始化仓库: git init ...
- 03-树3 Tree Traversals Again(25 point(s)) 【Tree】
03-树3 Tree Traversals Again(25 point(s)) An inorder binary tree traversal can be implemented in a no ...
- 激活win10企业长期服务版
win10 2016 长期服务版的ISO文件中本身就带有KMS激活KEY,不用输入任何KEY,连接网络进入CMD,只要输入:slmgr /skms kms.digiboy.irslmgr /ato这两 ...
- hdu1052 田忌赛马 —— 贪心
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1052 错误代码: #include<stdio.h>//田忌赛马,错误版 #include ...