Mysql DDL出現長時間等待MDL問題分析

給表新增字段時,發現鎖表了,查看進程,提示Waiting for table metadata lock,等待鎖釋放;然而蛋疼的是幾分鐘過去了,依然沒有任何的進展,特此記錄下這個問題的定位過程以及MDL的相關背景知識python

看到上面的表現,基本問題就來了mysql

  • Metadata Lock 是什麼鬼
  • 是什麼緣由致使一直等待

<!-- more -->git

I. 問題定位

首先須要確認什麼地方加鎖,從mysql出發,應該怎麼定位?github

1. 定位過程

對於mysql而言,通常來說上鎖和事物時伴生關係,因此咱們的直觀出發點就是查找db當前正在執行的事物sql

-- 查詢當前正在執行的事物的sql
SELECT * FROM information_schema.INNODB_TRX;

輸出結果以下,首先拿到事物對應的進程idbash

拿到id以後,則能夠分析對應的進程信息session

-- 查詢進程信息
show processlist

-- 查詢全部的進程信息
show full processlist

而後定位到具體的進程async

而後登錄到目標機器,查看端口號對應的進程,經過lsof命令查看tcp

lsof -i tcp:52951

從圖中能夠看出,是一個python進程的mysql鏈接開啓的事物,進程id爲5436oop

接着查看進程對應的信息

ps aux | grep 5436

這個腳本正是測試aiomysql的python腳本,內容比較簡單

import asyncio
import aiomysql

loop = asyncio.get_event_loop()


@asyncio.coroutine
def test_example():
    conn = yield from aiomysql.connect(host='127.0.0.1', port=3306,
                                       user='root', password='', db='test',
                                       loop=loop, autocommit=False)

    cur = yield from conn.cursor()
    yield from cur.execute("SELECT * from test_table")
    print(cur.description)
    r = yield from cur.fetchall()
    print(r)
    yield from cur.close()
    conn.close()

loop.run_until_complete(test_example())

2. 緣由分析

對python不太熟,直接藉助google查一下,發現有一樣的問題

這個問題拋出,在經過with打開鏈接獲取遊標後,執行mysql,可是沒有commit以前,會鎖表,這個期間修改表都會出現等待

下面近給出瞭解答,並無看到更多的深層次的說明,先記錄下,解決辦法就是在建立鏈接池的時候,選擇自動提交方式,而後就不會有這個問題了

pool = await aiomysql.create_pool(
    host="localhost",
    user="test",
    password="test",
    db="test",
    autocommit=True,
    cursorclass=DictCursor,
    loop=loop)

II. Metadata Lock說明

找到一篇文章說MDL的,推薦詳細閱讀 MySQL表結構變動你不可不知的Metadata Lock詳解

1. MDL 說明

抓一下核心的要點,簡單說一下看完這篇文章以後的樸素理解

MetaData Lock 簡稱爲MDL,簡單來講就是表的元數據鎖;當修改表結構的時候,就須要持有這個鎖

a. 做用

MDL的主要做用只有一點,保護一個正在執行的事物表結構不被修改

有一個原則,MDL是事物級別的,只有事物結束以後纔會釋放,而這裏面說的事物分爲兩類

  • 顯示事物:
    • 關閉autocommit
    • 以begin或start transaction開始的操做
  • AC-NL-RO(auto-commit non-locking read-only):
    • auto commit 開啓之下的select操做

b. 實例說明

直接看上面的說明,不太直觀,一個經典的case以下

session1 開啓了一個事物,執行查詢操做;可是如今session2 要刪除表,若是執行成功,那麼session1的第二次查詢就跪了,這樣就違背了事物的原則,全部在5.5版本引入了MDL,來保證在事物執行期間,表結構不被修改

2. 出現MDL等待緣由及解決方法

當咱們出現修改表結構,就須要獲取MDL的排他鎖,所以只有這個表沒有事物在執行時,才能獲取成功;當持有獨佔鎖以後,這個表的其餘操做將被阻塞(即不能插入數據,修改數據,也不能開啓事物操做)

所以在執行DDL時,一直出現等待MDL的時候,常見的緣由有下面三個

a. 長事物,阻塞DDL,從而阻塞全部同表的後續操做

經過 show processlist看到表上有正在進行的操做(包括讀),此時修改表時也會等待獲取MDL,這種時候解決辦法要麼就是等待執行完畢,要麼就是直接kill掉進程

b. 未提交事物,阻塞DDL

經過 show processlist沒有找到表上的操做,可是經過information_schema.innodb_trx發現有未提交的事物,

c. 異常的情況

經過 show processlist 和事物查詢都沒有的狀況下,可能的場景是一個顯示的事物中,對錶的操做出現了異常,雖然事物失敗,可是持有的鎖尚未釋放,也會致使這個緣由

能夠在performance_schema.events_statements_current表中查詢失敗的語句

3. MDL分類與sql實例

前面兩小節,分別說明什麼是MDL(樸素理解爲表的元數據鎖),以及當修改表時出現長時間的等待MDL的緣由分析;正常看完以後,應該會有下面的疑惑

  • MDL有哪些類型
  • 哪些sql會持有MDL

對於MDL的類型,從網上截一張圖

接下來須要分析下不一樣鎖模式對應的sql

屬性 含義 事例
MDL_INTENTION_EXCLUSIVE(IX) 意向排他鎖用於global和commit的加鎖。 truncate table t1; insert into t1 values(3,’abcde’); 會加以下鎖 (GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE)(SCHEMA,MDL_TRANSACTION,MDL_INTENTION_EXCLUSIVE)
MDL_SHARED(S) 只訪問元數據 好比表結構,不訪問數據。 set golbal_read_only =on 加鎖 (GLOBAL,MDL_EXPLICIT,MDL_SHARED)
MDL_SHARED_HIGH_PRIO(SH) 用於訪問information_scheam表,不涉及數據。 select * from information_schema.tables;show create table xx; desc xxx; 會加以下鎖: (TABLE,MDL_TRANSACTION,MDL_SHARED_HIGH_PRIO)
MDL_SHARED_READ(SR) 訪問表結構而且讀表數據 select * from t1; lock table t1 read; 會加以下鎖: (TABLE,MDL_TRANSACTION,MDL_SHARE_READ)
MDL_SHARED_WRITE(SW) 訪問表結構而且寫表數據 insert/update/delete/select .. for update 會加以下鎖:(TABLE,MDL_TRANSACTION,MDL_SHARE_WRITE)
MDL_SHARED_UPGRADABLE(SU) 是mysql5.6引入的新的metadata lock,能夠說是爲了online ddl 才引入的。特色是容許DML,防止DDL; alter table/create index/drop index 會加該鎖; 加入下鎖 (TABLE,MDL_TRANSACTION,MDL_SHARED_UPGRADABLE)
MDL_SHARED_NO_WRITE(SNW) 可升級鎖,訪問表結構而且讀寫表數據,而且禁止其它事務寫。 alter table t1 modify c bigint; (非onlineddl) (TABLE,MDL_TRANSACTION,MDL_SHARED_NO_WRITE)
MDL_SHARED_NO_READ_WRITE(SNRW) 可升級鎖,訪問表結構而且讀寫表數據,而且禁止其它事務讀寫。 lock table t1 write; 加鎖 (TABLE,MDL_TRANSACTION,MDL_SHARED_NO_READ_WRITE
MDL_EXCLUSIVE(X) 防止其餘線程讀寫元數據 CREATE/DROP/RENAME TABLE,其餘online DDL在rename階段也持有X鎖(TABLE,MDL_TRANSACTION,MDL_EXCLUSIVE)

4, 小結

上面的內容,可能信息量比較大,特別是MDL的鎖分類狀況,很難抓住重點,針對咱們平常接觸中,簡單給出小結

  • MDL是爲了保證事物執行過程當中,表結構不被修改引入的;所以修改表結構的前提是這個表上沒有事物(沒有正在執行,失敗,或者未提交的事物)
  • DDL執行,通常來說是須要獲取排他的MDL
  • DML都會開啓事物,所以會獲取 MDL_SW
  • DQL語句會獲取 MDL_SR

幾個簡稱的說明

  • MDL: metadata lock,能夠簡單理解爲表的元數據鎖
  • DDL: 數據定義語言,能夠簡單理解爲表的操做,如建立,修改,刪除表、視圖等,新增索引、字段等操做
  • DML: 數據操做語言,也就是咱們常規理解的 insert, update, delete 語句
  • DQL: 數據查詢語言,常見的select語句

幾個常見疑問解答

a. 爲何同一張表的多個DDL不能並行執行

  • MDL讀鎖是互相兼容的,能夠有多個增刪查改
  • MDL寫鎖是互斥的,只能有一個表的DDL

b. 爲何有時候DDL會卡住

  • MDL讀寫鎖之間是互斥的,因此若是DDL卡住,就證實有事務在執行,不能申請MDL寫鎖

c. 常見卡住的場景

  • 很是頻繁的業務高峯期
  • 有慢查詢把持着MDL讀鎖
  • 有事物一直未提交

d. 爲何須要MDL鎖

  • 當事務自己執行的時候理論上是不能容忍表結構在中途發生改變的

5. 更多參考

相關博文或者問答

II. 其餘

1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

一灰灰的我的博客,記錄全部學習和工做中的博文,歡迎你們前去逛逛

2. 聲明

盡信書則不如,已上內容,純屬一家之言,因我的能力有限,不免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

3. 掃描關注

一灰灰blog

QrCode

知識星球

goals

相關文章
相關標籤/搜索