MDL鎖(MetaData Lock,中繼資料鎖)是資料庫的內部鎖,用於確保執行DDL時事務使用的表中繼資料的一致性。普通讀寫事務需要擷取對應表的MDL讀鎖,DDL操作需要擷取對應表的MDL寫鎖。執行DDL時需要關注的MDL鎖相關問題如下:
阻塞性
長事務長期持有的MDL讀鎖會阻塞DDL的執行,這會使DDL因長時間申請MDL寫鎖不成功而失敗。此外,由於MySQL中MDL鎖是公平鎖,當DDL因為長事務持有MDL讀鎖而阻塞等待MDL寫鎖時,新事務也會因排隊申請MDL讀鎖而將被全部阻塞。
死結風險
多個DDL和事務一起執行時,由於申請MDL鎖的順序不同,可能引發MDL死結。
排它性
MDL寫鎖具有排它性,當DDL擷取到MDL寫鎖後,所有新來的事務都將因為無法申請MDL讀鎖而等待,這會造成流量跌零。雖然MySQL支援了Online DDL,但這類DDL只是儘力避免全程鎖表,在一些關鍵的環節仍需要短暫擷取MDL寫鎖。
執行DDL時一旦出現上述問題,可能導致Business Connectivity的堆積和阻塞,嚴重時可造成業務流量的暫時跌零,後果較為嚴重。PolarDB-X對上述MDL鎖的問題進行了針對性最佳化,使得執行DDL時不再需要擔心上述風險。
搶佔式MDL鎖最佳化
PolarDB-X支援搶佔式MDL鎖最佳化,該最佳化消除了執行DDL時由於MDL鎖的阻塞性導致的潛在風險。
支援版本
僅PolarDB-X的5.4.17-16952556及以上版本支援該功能。
詳細說明
執行需要申請MDL寫鎖的DDL時,如果申請MDL寫鎖的等鎖時間過長,PolarDB-X將自動停止阻塞該DDL的長事務所屬的串連。
下表展示了沒有搶佔式MDL鎖最佳化時,DDL和新事務被舊長事務阻塞的情形。
表1
步驟 | Session1 | Session2 | Session3 |
1 | begin; | - | begin; |
2 | insert into tb0 values(1); -- 擷取tb0的MDL讀鎖 | - | - |
3 | -- 長期不提交,類比長事務 | - | - |
4 | - | alter table tb0 add column col int; -- 嘗試擷取tb0的MDL寫鎖,被長事務阻塞 | - |
5 | - | - | select id from tb0; -- 嘗試擷取tb0的MDL讀鎖,被阻塞。 |
搶佔式MDL鎖最佳化後的執行過程如下(步驟與表1完全一致,關鍵步驟已在圖中標出):
可以看到,由於搶佔式MDL鎖最佳化機制,session1上的長事務所屬串連被斷開,保證了session2上的DDL順利執行,也確保了Session3上的新事務的正常執行。
分布式MDL死結檢測
PolarDB-X支援分布式MDL死結檢測,該功能可以檢測並打破在執行DDL時由MDL鎖參與形成的死結,維護DDL和事務的正常執行。
支援版本
僅PolarDB-X的5.4.17-16952556及以上版本支援該功能。
詳細說明
PolarDB-X將定時掃描事務和DDL之間的鎖等待情況,如果檢測到死結,PolarDB-X將自動停止一個普通事務,以確保DDL和其它事務的正常執行。
下表展示了一個典型的由MDL鎖參與的死結情境。
表2
步驟 | session1 | session2 | session3 | session4 |
1 | begin; -- 開啟事務1 | begin; -- 開啟事務2 | - | - |
2 | insert into t1 values(1); -- 擷取t1的MDL讀鎖 | insert into t2 values(1); -- 擷取t2的MDL讀鎖 | - | - |
3 | - | - | alter table t1 add column col int; -- 發起DDL1,嘗試擷取t1的MDL寫鎖,被阻塞 | alter table t2 add column col int; -- 發起DDL2,嘗試擷取t2的MDL寫鎖,被阻塞 |
4 | insert into t2 values(2); -- 嘗試獲得t2的MDL讀鎖。但因為MDL是公平鎖,所以被DDL2阻塞 | insert into t1 values(2); -- 嘗試獲得t1的MDL讀鎖。但因為MDL是公平鎖,所以被DDL1阻塞 | - | - |
如下示範了在具有分布式MDL死結檢測功能的PolarDB-X上,表2中的死結問題如何得到解決(執行步驟與上表完全一致,關鍵步驟已在圖中標出):
在按照表2裡的順序產生死結情境後,PolarDB-X檢測到了死結,並選擇斷開事務2所在的串連,事務2被復原,事務1和DDL1、DDL2順利執行。
雙版本MDL鎖最佳化
對於邏輯執行的DDL,PolarDB-X支援了雙版本中繼資料和對應的雙版本MDL鎖,這使得在執行這類DDL時,真正可以做到全程不鎖表、流量不跌零。
限制條件
該最佳化支援PolarDB-X中所有邏輯執行的DDL,判斷DDL是否為邏輯執行。詳情請參見Online DDL。
詳細說明
PolarDB-X的邏輯DDL基於Online Schema Change原理實現,將一個邏輯DDL的中繼資料版本細分為多個小版本,使得DDL的中繼資料版本演化可以在PolarDB-X執行個體中安全進行。例如PolarDB-X中的CREATE GLOBAL INDEX DDL
全程會涉及ABSENT(Vn),DELETE_ONLY(Vn+1),WRITE_ONLY(Vn+2),PUBLISH(Vn+3)多次版本切換。此外,PolarDB-X將MDL鎖與中繼資料的小版本綁定,每個版本的中繼資料都擁有各自對應版本的中繼資料鎖。
得益於Online Schema Change機制,在同一時刻,不僅叢集中的不同CN節點之間允許存在兩個版本,一個CN節點內部也允許存在兩個版本。因此當邏輯DDL開始中繼資料版本演化時,每一次演化,PolarDB-X只會擷取舊版本中繼資料對應的MDL寫鎖,因此新事務可以訪問新版本中繼資料,並申請新版本中繼資料對應的MDL讀鎖。
在雙版本中繼資料鎖的最佳化下,PolarDB-X的邏輯DDL可以做到全程不鎖表、流量不跌零。