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关 ...
随机推荐
- caffe搭建--vs2015+caffe+python3.5编译环境的搭建
修改build_win.cmd如下: @echo off @setlocal EnableDelayedExpansion :: Default values if DEFINED APPVEYOR ...
- 并发回射服务器的最基本实现思路( fork )
前言 一个服务器,通常会在一段时间内接收到多个请求.如果非要等到处理完一个请求再去处理下一个,势必会造成大部分用户的不满( 尤其当有某个请求需要占用大量时间时 ).如何解决这个问题?让处理这些用户请求 ...
- spring mvc 设置设置默认首页的方式
背景: 项目使用springmvc管理请求,有一个小的需求,输入域名的时候自动进入某个页面(或者说自动发起某个请求). 过程: 1,首先想到 在web.xml中配置welcome-file-list的 ...
- Cocos2d-JS 项目接入 触控广告平台(基于anysdk2.0.2)
本文以Cocos2d-JS项目作为示例,讲解如何集成AnySDK-JS. 一.如何创建项目我就省略了,直接进入主题. 1.1 首先,我需要下载anysdk框架包,下载地址:http://www.any ...
- Thumbelina,摘自iOS应用Snow White and more stories
Once upon a time there was a woman who wanted to have a child. 从前,有个想要个孩子的女人. A witch heard her wish ...
- JS中奇葩的假值
JavaScript中有 6 个值为“假”,这六个值是 false null undefined 0 '' (空字符串) NaN 这里面 false 本身是布尔类型,其它 5 个则不是. 除了这 6 ...
- ZFIND_ENHANCEMENT(找增强点-新)
REPORT ZFIND_ENHANCEMENT. *&-------------------------------------------------------------------- ...
- appium(1)-about appium
about appium Introduction to Appium Appium is an open-source tool for automating native, mobile web, ...
- ubuntu搭建mysql
步骤1 – 安装MySQL 在 Ubuntu 16.04 中,默认情况下,只有最新版本的 MySQL 包含在 APT 软件包存储库中.在撰写本文时,那是 MySQL 5.7 要安装它,只需更新服务器上 ...
- windows server 2008 + IIS 7.5实现多用户FTP(多账号对应不同目录
在windows server 2003 + IIS 6 的时候,就已经能实现多用户FTP的功能,不过设置有写繁琐,如果站点多的话,设置账号.权限这些东西都要搞很久.Windows server 20 ...