MySQL · 捉虫动态 · 5.7 mysql_upgrade 元数据锁等待

问题描述

如下图,mysql_upgrade 过程中,执行 DROP DATABASE IF EXISTS performance_schema 一直在等待 metadata lock

问题排查

简单粗暴的方法

有一种简单的解决方法,把其他连接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 获取锁等待信息

ps aux | grep 端口号,找出mysqld进程号 pid,pstack pid > stack.log

在stack.log中搜索 acquire_lock(请求mdl锁的函数),可以看出是 thread 3 在请求元数据锁

gdb -p pid
thread 3
切换到目标线程

#0  0x0000003fe940ba5e in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x0000000000bd3fb2 in native_cond_timedwait (this=0x7eff640e05d8, owner=0x7eff640e0540, abs_timeout=0x7effa83b2ce0, set_status_on_timeout=Unhandled dwarf expression opcode 0xf3
)
#2  my_cond_timedwait (this=0x7eff640e05d8, owner=0x7eff640e0540, abs_timeout=0x7effa83b2ce0, set_status_on_timeout=Unhandled dwarf expression opcode 0xf3
)
#3  inline_mysql_cond_timedwait (this=0x7eff640e05d8, owner=0x7eff640e0540, abs_timeout=0x7effa83b2ce0, set_status_on_timeout=Unhandled dwarf expression opcode 0xf3
)
#4  MDL_wait::timed_wait (this=0x7eff640e05d8, owner=0x7eff640e0540, abs_timeout=0x7effa83b2ce0, set_status_on_timeout=Unhandled dwarf expression opcode 0xf3
)
#5  0x0000000000bd6048 in MDL_context::acquire_lock (this=0x7eff640e05d8, mdl_request=0x7eff640aa870, lock_wait_timeout=Unhandled dwarf expression opcode 0xf3
) 

f 5
跳转到  MDL_context::acquire_lock
acquire_lock 函数参数中有 MDL_request
MDL_request::MDL_key 中有详细的锁信息

p mdl_request->key

{m_length = 34, m_db_name_length = 18, m_ptr = "\003performance_schema\000global_status", '\000' <repeats 353 times>, static m_namespace_to_wait_state_name = \{ \{m_key = 0,
  m_name = 0x130aa9b "Waiting for global read lock", m_flags = 0}, {m_key = 0, m_name = 0x130abb0 "Waiting for tablespace metadata lock", m_flags = 0}, {m_key = 0,
  m_name = 0x130abd8 "Waiting for schema metadata lock", m_flags = 0}, {m_key = 0, m_name = 0x130ac00 "Waiting for table metadata lock", m_flags = 0}, {m_key = 0,
  m_name = 0x130ac20 "Waiting for stored function metadata lock", m_flags = 0}, {m_key = 0, m_name = 0x130ac50 "Waiting for stored procedure metadata lock", m_flags = 0}, {m_key = 0,
  m_name = 0x130ac80 "Waiting for trigger metadata lock", m_flags = 0}, {m_key = 0, m_name = 0x130aca8 "Waiting for event metadata lock", m_flags = 0}, {m_key = 0,
  m_name = 0x130aab8 "Waiting for commit lock", m_flags = 0}, {m_key = 0, m_name = 0x130aad0 "User lock", m_flags = 0}, {m_key = 0, m_name = 0x130acc8 "Waiting for locking service lock",
  m_flags = 0} } }

上述信息可以看出,正在请求performance_schema.global_status这张表的锁

排查业务代码

和业务方确认,agent中确实执行了 “show global status” , 但是已经设置了autocommit

简化逻辑后,agent代码如下

import MySQLdb
from time import sleep
conn = MySQLdb.connect(host='47.93.49.119', port=3001, user='xx1')
conn.autocommit = True
cur=conn.cursor()
cur.execute("show global status")
while 1:
    sleep(1)

代码中确实设置了autocommit,但是并没有生效(如果执行了commit,不可能不释放元数据锁)

MySQLdb.connect 返回 Connection 类,根据上述代码,autocommit是 Connection的成员属性

class Connection(_mysql.connection):

Connection 继承自_mysql.connection,_mysql 是c语言实现的python库,查看_mysql.c

static PyMethodDef _mysql_ConnectionObject_methods[] = {
    {
        "affected_rows",
        (PyCFunction)_mysql_ConnectionObject_affected_rows,
        METH_VARARGS,
        _mysql_ConnectionObject_affected_rows__doc__
    },
    {
        "autocommit",
        (PyCFunction)_mysql_ConnectionObject_autocommit,
        METH_VARARGS,
        _mysql_ConnectionObject_autocommit__doc__
    },
    {
        "commit",
        (PyCFunction)_mysql_ConnectionObject_commit,
        METH_VARARGS,
        _mysql_ConnectionObject_commit__doc__
    },

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

时间: 2024-09-30 20:06:32

MySQL · 捉虫动态 · 5.7 mysql_upgrade 元数据锁等待的相关文章

MySQL · 捉虫动态 · 唯一键约束失效

唯一键是数据库设计中常用的索引类型,主要用于约束数据,不允许出现重复的键值记录.可以想象,如果唯一键约束失效了,将可能产生可怕的逻辑错误.本文主要讨论下最近MySQL爆出来的两个唯一键约束失效导致二级索引corruption的问题. 问题一: 检查重复键加锁逻辑不当 影响版本:MySQL 5.6.21之前,5.6.12之后的版本 介绍分析 在5.6.12之前的版本中,当插入一条带唯一约束的记录时,如果表上已经存在了这条记录,或者有一条标记删除的相同键值记录时,就需要对这条记录加S GAP (类型

MySQL · 捉虫动态 · MySQL DDL BUG

背景 MySQL保存了两份元数据,一份在server层,保存在FRM文件中,另外一份在引擎层,比如InnoDB的数据字典中,这样也就造成了DDL语句经常导致元数据不一致的情况,下面介绍两个近期出现的因为DDL产生的bug. rename 外键引用的column BUG复现过程 CREATE TABLE t1 (a INT NOT NULL, b INT NOT NULL, INDEX idx(a)) ENGINE=InnoDB; CREATE TABLE t2 (a INT KEY, b INT

MySQL · 捉虫动态 · ORDER/GROUP BY 导致 mysqld crash

问题描述 表结构如下所示: show create table test\G Table: test Create Table: CREATE TABLE `test` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id2` varchar(50) DEFAULT NULL `id3` varchar(100) DEFAULT NULL `some_text` varchar(200) DEFAULT NULL `name` varchar(

MySQL · 捉虫动态 · 信号处理机制分析

背景 在 AliSQL 上面有人提交了一个 bug,在使用主备的时候 service stop mysql 不能关闭主库,一直显示 shutting down mysql -,到底怎么回事呢,先来看一下 service stop mysql 是怎么停止数据库的.配置 MySQL 在系统启动时启动需要把 MYSQL_BASEDIR/support-files 目录下的脚本 mysql.sever 放到 /etc/init.d/ 目录下,脚本来控制 mysqld 的启动和停止.看一下脚本中的代码 :

MySQL · 捉虫动态 · left-join多表导致crash

有一天小编胡乱写SQL, left join了30张表, 结果导致了Mysql server gone away- 我们来看看crash堆栈 <signal handler called> base_list_iterator::next update_ref_and_keys make_join_statistics JOIN::optimize mysql_execute_select 可以看出, 在产生执行计划过程中crash了. 追查 堆栈表明, update_ref_and_keys

MySQL · 捉虫动态 · ALTER IGNORE TABLE导致主备不一致

背景 我们知道当一张表的某个字段存在重复值时,这个字段没办法直接加UNIQUE KEY,但是MySQL提供了一个 ALTER IGNORE TABLE的方式,可以忽略修改表结构过程中出现的错误,但是要忽略UNIQUE重复值,就需要打开old_alter_table,也就是拷贝表的方式来ALTER TABLE. 例如这样: CREATE TABLE t1(c1 int) ENGINE = InnoDB; INSERT INTO t1 VALUES (1), (1); SET old_alter_t

MySQL · 捉虫动态 · show binary logs 灵异事件

问题背景 最近在运维 MySQL 中遇到一个神奇的问题,分享给大家.现象是这样的,show binary logs 没有返回结果,flush binary logs 后也不行, 但是 binlog 是正常工作的,show master staus 是有输出的. mysql> show binary logs; Empty set (0.00 sec) mysql> show master status\G *************************** 1. row *********

MySQL · 捉虫动态 · MySQL 外键异常分析

外键约束异常现象 如下测例中,没有违反引用约束的插入失败. create database `a-b`; use `a-b`; SET FOREIGN_KEY_CHECKS=0; create table t1(c1 int primary key, c2 int) engine=innodb; create table t2(c1 int primary key, c2 int) engine=innodb; alter table t2 add foreign key(c2) referen

MySQL · 捉虫动态 · order by limit 造成优化器选择索引错误

问题描述 bug 触发条件如下: 优化器先选择了 where 条件中字段的索引,该索引过滤性较好: SQL 中必须有 order by limit 从而引导优化器尝试使用 order by 字段上的索引进行优化,最终因代价问题没有成功. 复现case 表结构 create table t1( id int auto_increment primary key, a int, b int, c int, key iabc (a, b, c), key ic (c) ) engine = innod