【MySQL】MetaData Lock 之三
一 簡介
通過前面兩篇文章的介紹,相信讀到這裡的各位對MDL 鎖已經有了比較深入的瞭解了,本文將結合理論知識介紹幾組MDL 鎖的案例。
二 常見MDL 鎖的場景
1 Waiting for global read lock
我們先構造一個Waiting for global read lock場景:
session1: alter table t1 add c3 bigint; //大表執行需較長時間
session2: set global read only=on; //等待
檢視
分析:
alter table t1 add c3 bigint;會加(GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE) 語句結束後才釋放
set global read only=on; 會加(GLOBAL,MDL_EXPLICIT,MDL_SHARED)
由於session1執行時間比較長,一直持有MDL_INTENTION_EXCLUSIVE。從相容性矩陣可以看出MDL_SHARED和MDL_INTENTION_EXCLUSIVE是不相容的,因此發生“Waiting for global read lock ”等待。直到session 1 alter操作完成釋放MDL_INTENTION_EXCLUSIVE。set global read only=on;才可以繼續執行。
2.2 Waiting for commit lock
session1:
begin;
insert into t1 vlaues(null, 'ab');
session2:
flush table with read lock;//成功
session1: commit //發生等待
mysql> show processlist;
分析:
flush table with read lock;持有(COMMIT,MDL_EXPLICIT,MDL_SHARED)
commit時上(COMMIT,MDL_EXPLICIT,MDL_INTENTION_EXCLUSIVE)鎖
MDL_SHARED和MDL_INTENTION_EXCLUSIVE是不相容的,因此發生等待.
2.3 Waiting for table metadata lock
這個是比較常見的鎖等待,總結下來有如下幾種場景
1 長查詢/mysqldump 阻塞DDL
會話1先執行select ,會話2後執行alter,在會話1執行完畢前,會話2拿不到MDL鎖,從表格上面來看,主要阻塞在rename階段。會話1在執行完畢後,會話2拿到MDL鎖,變為rename table狀態,這個操作持續時間非常短,會話1再次執行查詢,當會話2執行完後,此時會話1正常執行。這說明對於MDL鎖而言,select會阻塞alter,而alter不會阻塞select。在rename的瞬間,alter是會阻塞select的.
當執行select語句時,只要select語句在獲取MDL_SHARED_READ鎖之前,alter沒有執行到rename階段,那麼select獲取MDL_SHARED_READ鎖成功,後續有alter執行到rename階段,請求MDL_EXCLUSIVE鎖時,就會被阻塞。rename階段會持有MDL_EXCLUSIVE鎖,但由於這個過程時間非常短(大頭都在copy資料階段),並且是alter的最後一個階段,所以基本感覺不到alter會阻塞select語句。由於MDL鎖在事務提交後才釋放,若線上存在大查詢,或者存在未提交的事務,則會出現ddl卡住的現象。這裡要注意的是,ddl卡住後,若再有select查詢或DML進來,都會被堵住,就會出現threadrunning飆高的情況。
2 未提交的事務阻塞 DDL
session1 對錶t進行update操作,存在未提交的事務,故一直持有 MDL_SHARED_WRITE鎖,由於沒有執行COMMIT,會一直持有。session2 DDL 操作會請求TABLE-TRANSACTION-EXCLUSIVE鎖,該鎖與session1 的MDL_SHARED_WRITE 鎖互斥,故 session2 的DDL 等待;session3的查詢操作會請求TABLE- TRANSACTION- MDL_SHARED_READ鎖,雖然MDL_SHARED_READ與活躍鎖MDL_SHARED_WRITE不衝突,但是與session2的等待鎖EXCLUSIVE衝突,因此也會等待。
解決該中場景的問題比較麻煩,但從show processlist 不能檢查出哪個會話持有鎖 。可以從兩個方面進行調查
a 查詢 information_schema.innodb_trx
b 檢查 show engine innodb status ;
active N sec 說明事務持續了N秒,一般而言超過10秒的事務都是有問題的 。找到了活動的事務之後,要和開發溝通看看如何處理,能否直接kill 該回話? 根據和開發溝通的結果採取相應的措施。
3 第1種情況的特例,存在一個查詢失敗的語句,比如查詢不存在的列,語句失敗返回,但是事務沒有提交,此時alter仍然會被堵住。
通過show processlist看不到TableA上有任何操作,在information_schema.innodb_trx中也沒有任何進行中的事務。這很可能是因為在一個顯式的事務中,對TableA進行了一個失敗的操作(比如查詢了一個不存在的欄位),這時事務沒有開始,但是失敗語句獲取到的鎖依然有效。從performance_schema.events_statements_current表中可以查到失敗的語句。
官方手冊上對此的說明如下:
If the server acquires metadata locks for a statement that is syntactically valid but fails during execution, it does not release the locks early. Lock release is still deferred to the end of the transaction because the failed statement is written to the binary log and the locks protect log consistency.
也就是說除了語法錯誤,其他錯誤語句獲取到的鎖在這個事務提交或回滾之前,仍然不會釋放掉。because the failed statement is written to the binary log and the locks protect log consistency 但是解釋這一行為的原因很難理解,因為錯誤的語句根本不會被記錄到二進位制日誌。
三 參考
[1] 《MySQL出現Waiting for table metadata lock的場景淺析》
[2] 《MySQL中 metadata lock問題分析》
[3] 《官方Metadata Lock 介紹》
如果您覺得從這篇文章受益,可以微信支付贊助 北在南方 一瓶飲料 ^_^
通過前面兩篇文章的介紹,相信讀到這裡的各位對MDL 鎖已經有了比較深入的瞭解了,本文將結合理論知識介紹幾組MDL 鎖的案例。
二 常見MDL 鎖的場景
1 Waiting for global read lock
我們先構造一個Waiting for global read lock場景:
session1: alter table t1 add c3 bigint; //大表執行需較長時間
session2: set global read only=on; //等待
檢視
-
mysql> show processlist;
-
+----+------+-----------------+------+---------+------+------------------------------+------------------------------+
-
| Id | User | Host | db | Command | Time | State | Info |
-
+----+------+-----------------+------+---------+------+------------------------------+------------------------------+
-
| 1 | root | localhost:5202 | test | Query | 12 | altering table | alter table t1 add c3 bigint |
-
| 2 | root | localhost:14699 | test | Query | 3 | Waiting for global read lock | set global read_only=on |
-
| 3 | root | localhost:17085 | NULL | Query | 0 | init | show processlist |
- +----+------+-----------------+------+---------+------+------------------------------+------------------------------+
alter table t1 add c3 bigint;會加(GLOBAL,MDL_STATEMENT,MDL_INTENTION_EXCLUSIVE) 語句結束後才釋放
set global read only=on; 會加(GLOBAL,MDL_EXPLICIT,MDL_SHARED)
由於session1執行時間比較長,一直持有MDL_INTENTION_EXCLUSIVE。從相容性矩陣可以看出MDL_SHARED和MDL_INTENTION_EXCLUSIVE是不相容的,因此發生“Waiting for global read lock ”等待。直到session 1 alter操作完成釋放MDL_INTENTION_EXCLUSIVE。set global read only=on;才可以繼續執行。
2.2 Waiting for commit lock
session1:
begin;
insert into t1 vlaues(null, 'ab');
session2:
flush table with read lock;//成功
session1: commit //發生等待
mysql> show processlist;
-
+----+------+-----------------+------+------------+------+-------------------------+------------------+
-
| Id | User | Host | db | Command | Time | State | Info |
-
+----+------+-----------------+------+------------+------+-------------------------+------------------+
-
| 1 | root | 127.0.0.1:5202 | test | Query | 7 | Waiting for commit lock | commit |
-
| 2 | root | 127.0.0.1:14699 | test | Sleep | 13 | | NULL |
-
| 3 | root | 127.0.0.1:17085 | NULL | Query | 0 | init | show processlist |
- +----+------+-----------------+------+---------+------+-------------------------+------------------+
flush table with read lock;持有(COMMIT,MDL_EXPLICIT,MDL_SHARED)
commit時上(COMMIT,MDL_EXPLICIT,MDL_INTENTION_EXCLUSIVE)鎖
MDL_SHARED和MDL_INTENTION_EXCLUSIVE是不相容的,因此發生等待.
2.3 Waiting for table metadata lock
這個是比較常見的鎖等待,總結下來有如下幾種場景
1 長查詢/mysqldump 阻塞DDL
session1 | session2 | session3 |
Select count(*) from t; | ||
alter table t add column c3 int; |
||
Show processlist; session2:copy to tmp table |
||
阻塞 |
Show processlist; session2:Waiting for table metadata lock |
|
A:執行完畢 | ||
Show processlist; session2:rename table |
||
Select count(*) from t; | ||
B:執行完畢 | ||
Show processlist; session1: Sending data |
會話1先執行select ,會話2後執行alter,在會話1執行完畢前,會話2拿不到MDL鎖,從表格上面來看,主要阻塞在rename階段。會話1在執行完畢後,會話2拿到MDL鎖,變為rename table狀態,這個操作持續時間非常短,會話1再次執行查詢,當會話2執行完後,此時會話1正常執行。這說明對於MDL鎖而言,select會阻塞alter,而alter不會阻塞select。在rename的瞬間,alter是會阻塞select的.
當執行select語句時,只要select語句在獲取MDL_SHARED_READ鎖之前,alter沒有執行到rename階段,那麼select獲取MDL_SHARED_READ鎖成功,後續有alter執行到rename階段,請求MDL_EXCLUSIVE鎖時,就會被阻塞。rename階段會持有MDL_EXCLUSIVE鎖,但由於這個過程時間非常短(大頭都在copy資料階段),並且是alter的最後一個階段,所以基本感覺不到alter會阻塞select語句。由於MDL鎖在事務提交後才釋放,若線上存在大查詢,或者存在未提交的事務,則會出現ddl卡住的現象。這裡要注意的是,ddl卡住後,若再有select查詢或DML進來,都會被堵住,就會出現threadrunning飆高的情況。
session1 | session2 | session3 |
begin; update t set where id=3; |
||
alter table t add column c3 int;//hang |
||
Show processlist; session2:Waiting for table metadata lock |
||
Select count(*) from t;//hang | ||
Show processlist; session2:Waiting for table metadata lock session3:Waiting for table metadata lock |
session1 對錶t進行update操作,存在未提交的事務,故一直持有 MDL_SHARED_WRITE鎖,由於沒有執行COMMIT,會一直持有。session2 DDL 操作會請求TABLE-TRANSACTION-EXCLUSIVE鎖,該鎖與session1 的MDL_SHARED_WRITE 鎖互斥,故 session2 的DDL 等待;session3的查詢操作會請求TABLE- TRANSACTION- MDL_SHARED_READ鎖,雖然MDL_SHARED_READ與活躍鎖MDL_SHARED_WRITE不衝突,但是與session2的等待鎖EXCLUSIVE衝突,因此也會等待。
解決該中場景的問題比較麻煩,但從show processlist 不能檢查出哪個會話持有鎖 。可以從兩個方面進行調查
a 查詢 information_schema.innodb_trx
b 檢查 show engine innodb status ;
active N sec 說明事務持續了N秒,一般而言超過10秒的事務都是有問題的 。找到了活動的事務之後,要和開發溝通看看如何處理,能否直接kill 該回話? 根據和開發溝通的結果採取相應的措施。
3 第1種情況的特例,存在一個查詢失敗的語句,比如查詢不存在的列,語句失敗返回,但是事務沒有提交,此時alter仍然會被堵住。
通過show processlist看不到TableA上有任何操作,在information_schema.innodb_trx中也沒有任何進行中的事務。這很可能是因為在一個顯式的事務中,對TableA進行了一個失敗的操作(比如查詢了一個不存在的欄位),這時事務沒有開始,但是失敗語句獲取到的鎖依然有效。從performance_schema.events_statements_current表中可以查到失敗的語句。
官方手冊上對此的說明如下:
If the server acquires metadata locks for a statement that is syntactically valid but fails during execution, it does not release the locks early. Lock release is still deferred to the end of the transaction because the failed statement is written to the binary log and the locks protect log consistency.
也就是說除了語法錯誤,其他錯誤語句獲取到的鎖在這個事務提交或回滾之前,仍然不會釋放掉。because the failed statement is written to the binary log and the locks protect log consistency 但是解釋這一行為的原因很難理解,因為錯誤的語句根本不會被記錄到二進位制日誌。
三 參考
[1] 《MySQL出現Waiting for table metadata lock的場景淺析》
[2] 《MySQL中 metadata lock問題分析》
[3] 《官方Metadata Lock 介紹》
如果您覺得從這篇文章受益,可以微信支付贊助 北在南方 一瓶飲料 ^_^
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-1791744/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mysql觀測METADATA LOCK(MDL)鎖MySql
- MySQL新增索引偶遇waiting for table metadata lockMySql索引AI
- MySQL DDL Waiting for table metadata lock 解決MySqlAI
- mysql metadata lock後設資料鎖之鎖狀態lock_status流轉圖MySql
- MySQL表結構變更引起的Metadata Lock|如何定位DDL被阻塞MySql
- mysql lock操作MySql
- MySQL8.0 binlog_row_metadataMySql
- MySQL:理解MDL LockMySql
- mysql innodb lock鎖之record lock之一MySql
- MySQL:Innodb 讓MDL LOCK和ROW LOCK 記錄到errlogMySql
- MySQL-lock(鎖)-v2.0MySql
- MySQL:MDL LOCK的“穿越行為”MySql
- MySQL的GET_LOCK函式MySql函式
- MySQL5.7 Waiting for global read lockMySqlAI
- Qt MetadataQT
- MySQL更新卡住報錯lock wait timeoutMySqlAI
- PHP面試之三:MySQL資料庫PHP面試MySql資料庫
- MySQL 共享鎖 (lock in share mode),排他鎖 (for update)MySql
- mysql, Lock wait timeout exceeded; try restarting 解決MySqlAIREST
- 2.3.2.2.1 Metadata Links
- 解析arxiv Metadata
- 8.11.4 Metadata Locking
- mysql鎖之三種行級鎖介紹MySql
- 從Mysql slave system lock延遲說開去MySql
- MySql報錯:Lock wait timeout exceeded: try restadina transactionMySqlAIREST
- @EnableAsync annotation metadata was not injected
- ASM Metadata Dump UtilityASM
- 2.1.3.2 Metadata and Data Links
- MySQL 5.7從庫system lock執行緒解釋MySql執行緒
- MySQL:簡單記錄一下Waiting for commit lockMySqlAIMIT
- Full GC (Metadata GC Threshold)GC
- Guideline 2.3.10 - Performance - Accurate MetadataGUIIDEORM
- mysql關於FLUSH TABLES和FLUSH TABLES WITH READ LOCK的理解MySql
- MySQL RC隔離級別下罕見的gap lockMySql
- MySQL next-key lock 加鎖範圍是什麼?MySql
- Swift 5 Type Metadata 詳解Swift
- Lock 鎖
- 資料庫對比系列之三(PG事務與MySQL事務)資料庫MySql
- MySQL 8.0 Reference Manual(讀書筆記66節--locking read 與lock)MySql筆記