Mysql 中的MDL

 

文章正文:

本文可以結合 MySQL中的事務原理和鎖機制 查看。

首先簡單瞭解一下 mysql 的 sql 類型:

1、數據定義語言 DDL:Create、Drop、Alter 操作。用於定義庫和表結構的。

2、數據查詢語言 DQL:select。用於查詢數據的。

3、數據操縱語言 DML:insert、update、delete。對行記錄進行增刪改操作。

4、數據控制語言 DCL:grant、revoke、commit、rollback。控制數據庫的權限和事務。

MDL

MDL(MetaData Lock)就是針對於 DDL 與 DML、DQL 操作加鎖,執行 DDL 自動添加寫鎖,執行 DML、DQL 自動添加讀鎖,也就是說 DML 語句可以同時執行(不考慮其他鎖),而 DDL 間則會相互阻塞。

爲什麼在執行 DDL 時會添加寫鎖?

DDL 在執行會先創建一個臨時表,先將表的數據全部移到這個臨時表中,然後再將臨時表替換當前表。在這個過程中如果出現讀寫操作就會影響最終結果出錯。這個過程耗時主要在將原表的數據移到臨時表的過程。

 

執行

不同事務的執行是按隊列順序進行的,如果兩個事務所執行的 MDL 添加的分別是讀、寫鎖,那麼就會互斥,後面的事務只有等到前面事務提交釋放鎖後才能執行。

例子:假設有四個會話:session1、session2、session3、session4 ,首先先依次開啓事務,然後session1,session2 先執行查詢操作(爲了避免可能是可串行化級別導致加的寫鎖衝突,所以就使用查詢操作),session1,session2 中的操作可以正常執行,session3執行 Alter 修改表結構,此時 session3 的操作就會阻塞(因爲 MDL 的讀寫鎖衝突),session4 再執行增刪改查也會被阻塞,因爲是在隊列中,它位於 session3 後面,所以只有等到 session3 提交後其才能繼續執行。

Online DDL

通過上面的分析,進行實踐檢驗,卻出現了下面的情況:

 

可以看到執行和顯示順序是圖中標註的從1開始遞增按順序執行的。可以看到 session4 在 session2 提交後就立刻會執行,並且在 session4 提交後 session3 才能執行成功,這個和前面所說的理論就會衝突。這個原因是當前 mysql 版本是5.6,而在 mysql 5.6 支持 Online DDL。

Online DDL 是對 MDL 的一種優化,因爲如果按照 MDL 的執行邏輯,像上面這種情況,一旦一些簡單的讀寫操作比某一條 DDL 語句啓動慢一些,就會陷入阻塞,如果 DDL 修改的是大表且是高頻表,那麼在這條語句執行時會阻塞所有的讀寫操作,很容易使數據庫崩潰。而 Online DDL 優化思路就是在獲取到鎖之後先允許一段時間的讀寫操作,直到臨時表的數據轉移完成,再停止其他讀寫操作,而具體實現就主要分爲下面幾步,

1. 拿MDL寫鎖

2. 降級成MDL讀鎖,接受讀寫操作,讀操作直接正常返回,寫操作會被記錄下來,等待後面更新到臨時表中。

3. 真正做DDL,在 DDL 表記錄向臨時錶轉移完成並執行完記錄的寫操作後開始阻塞讀寫操作。

4. 升級成MDL寫鎖,進行臨時表的替換

5. 釋放MDL鎖

應用於上面的例子就是:

1、session1、session2 因爲是隊列的前兩個,先添加MDL讀鎖,正常執行,session3 因爲是要添加 MDL 寫鎖所以阻塞,session4 在 session3 後面所以也阻塞,session1、session2執行完成提交釋放讀鎖。

2、session3 在獲取到 MDL 寫鎖後,會先進行降級降級成讀鎖

3、在 session3 降級後 session4 因爲是 MDL 讀鎖,所以也會獲取到鎖,執行

4、session3 在完成向臨時表數據遷移以及執行完記錄的寫操作後想升級回寫鎖發現當前的讀鎖還被 session4 佔用,所以會阻塞,等待 session4 執行釋放。

5、session4 提交事務,釋放讀鎖,session3 成功升級鎖,輸出提示語句,最後提交。

注意:

1、如果前面的例子還有一個 session5,並且在一開始和 session4 一起開啓事務、查詢,那麼在 session2 提交後 session5 也會隨着 session4 一起執行,而 session3 則需要等待 session4、session5 提交後才能執行第四步。

  而如果 session5 開啓事務是在 session3 向臨時表數據遷移完成後,那麼 session5 的查詢操作就會被 session3 阻塞,直到 session3 提交事務。

2、Online DDL 整個過程是在 InnoDB 內部執行的,對於 Server 來說並沒有什麼操作,所以這個操作是 "inplace" 的,也就是說:

  Online 過程一定是 inplace 的,但 inplace 過程不一定是 Online 的。

3、5.6 開始因爲支持 Online DDL,所以在向臨時表遷移數據時可能會積攢一些寫操作造成頁分裂,同時在創建新表時每個數據頁還會留 1/16 的空間用於更新操作,所以執行DDL後的表結構不一定是最 "緊湊" 的。

 

 

MDL 引發的問題

在上線項目中,如果需要對某個大表的字段進行刪除,那麼必然會阻塞該表的所有增刪改查操作,如果該表存儲了熱點數據,那麼就會阻塞大量的操作,最終導致數據庫崩潰。

解決

1、查看當前是否存在長事務,如果存在,先儘快將其提交,防止長事務的MDL寫鎖阻塞
2、爲 DDL 的操作設置過期時間,如果時間內沒有成功執行就取消。可以使用 Github 的開源工具 gh-ost。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章