如下圖,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
為了說服業務方,我們繼續排查是在等待什麼鎖
首先想到5.7的 performance_schema.metadata_locks ,很遺憾這張表裡并沒有記錄
我們嘗試使用 gdb 擷取鎖等待資訊
<code>ps aux | grep 端口号</code>,找出mysqld程序号 pid,<code>pstack pid > stack.log</code>
在stack.log中搜尋 acquire_lock(請求mdl鎖的函數),可以看出是 thread 3 在請求中繼資料鎖
上述資訊可以看出,正在請求performance_schema.global_status這張表的鎖
和業務方确認,agent中确實執行了 “show global status” , 但是已經設定了autocommit
簡化邏輯後,agent代碼如下
代碼中确實設定了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