有一种简单的解决方法,把其他连接kill掉,释放 metadata lock
对于这个案例,占用元数据锁的是 Id = 107768,User = xx1 的连接
但是这种方法指标不治本,案例中占用元数据锁的连接,是一个agent服务建立的
mysql_upgrade也是程序执行,不能每次都手工kill连接,需要查明为什么占用锁
详细查明问题原因
据业务方反馈,agent服务和调用mysql_upgrade的代码和5.6也在用,没有出现问题。
怀疑是5.7引入的bug
根据上述现象,显然是agent占了metadata lock,大概率不是mysql的bug
查询 performance_schema.metadata_locks
首先想到5.7的 performance_schema.metadata_locks ,很遗憾这张表里并没有记录
gdb 获取元数据锁信息
我们尝试使用 gdb 获取锁等待信息
,找出mysqld进程号 pid,pstack pid > stack.log
在stack.log中搜索 acquire_lock(请求mdl锁的函数),可以看出是 thread 3 在请求元数据锁
上述信息可以看出,正在请求performance_schema.global_status这张表的锁
排查业务代码
和业务方确认,agent中确实执行了 “show global status” , 但是已经设置了autocommit
代码中确实设置了autocommit,但是并没有生效(如果执行了commit,不可能不释放元数据锁)
MySQLdb.connect 返回 Connection 类,根据上述代码,autocommit是 Connection的成员属性
Connection 继承自_mysql.connection,_mysql 是c语言实现的python库,查看_mysql.c
autommit 并不是成员属性,而是一个成员方法
conn.autocommit = True 强行将 autocommit 的函数指针赋值为 True,并没有真正设置autocommit
5.6中没有发现这个问题
一是 agent 中只有查询语句,不设autocommit也能返回查询结果
二是 5.6中 “show global status” 查询的是 information_shcema,5.7中是performance_schema,5.6中不会影响 drop database performance_schema