Flink CDC 引起的 MySQL 元數據鎖
記一次Flink CDC引起的MySQL元數據鎖事故,總結經驗教訓。后續在編寫Flink CDC任務時,要處理好異常,避免產生長時間的元數據鎖。同時出現生產問題時要及時排查,不能抱有僥幸心理。
一、事件經過
某天上午,收到系統的告警信息,告警提示:同步MySQL的某張表數據到Elasticsearch異常,提示連不上Mysql,當時沒有太上心,以為可能是偶爾網絡異常。
然后立馬大量用戶開始投訴系統使用有問題,同時聽到有同事反饋內部系統數據導不出來。此時我慌了。
立馬看了微服務網關、用戶中心服務、部分流量比較大的BFF層服務,CPU、內存、磁盤等都是正常的。但是Pod出現了健康檢查失敗的情況。
于是又趕緊看了日志,出現了大量拿不到MySQL Connection異常。
又趕緊看了MySQL情況,CPU、內存、磁盤都是正常的,但是出現了許多奇怪的慢SQL。
此時我大概猜測到了可能是什么操作鎖表了,導致大量Connection無法釋放,又趕緊看了Mysql鎖的情況,果然發現了大量的元數據鎖,高達400多個Connection沒釋放。
二、處理步驟
既然出現了元數據鎖,導致這么多Connection沒有釋放,那就找出占用時間最長的那個會話kill掉。陸續kill了幾個會話后,系統恢復了。
系統恢復后,又去看了慢SQL,發現主要有兩塊高頻慢SQL,一塊是Flink相關的,另一塊是Nacos相關的。后來經過分析:元數據鎖是因為Flink CDC執行FLUSH TABLES WITH READ LOCK導致的,跟Nacos無關,Nacos只是個煙霧彈。
# Flink相關的:
SHOW CREATE TABLE `xxx_db`.`xxx_table`;
FLUSH TABLES WITH READ LOCK;
# Nacos相關的:
DELETE FROM config_info WHERE data_id='com.alibaba.nacos.testMasterDB';
防止事故再次發生,又把Flink CDC任務里的SQL方式換成了API方式。Flink CDC使用SQL方式時,會產生大量任務,占用更多的資源,也容易出現任務異常。
三、原因分析
1.元數據鎖
(1) 以上關于鎖的截圖,可以看到是元數據鎖引發的Connection被耗盡,那什么是元數據鎖:
- 元數據鎖(Meta Data Lock,MDL),用于鎖定數據庫對象的元數據,例如:表、索引、視圖等的結構信息。通常用于保證并發的數據定義語言(DDL)操作的一致性,防止在修改表結構的過程中出現并發問題。
- 其作用是用于解決DDL操作與DML操作的一致性;通常,DDL操作需要獲取MDL寫鎖,并且MDL鎖一旦發生,就可能會對數據庫的性能影響,因為后續對該表的任何Select、DML、DDL操作都會被阻塞,造成Connection積壓。
(2) 為什么要有元數據鎖:
主要為了保證元數據的一致性,用于處理不同線程操作同一數據對象的同步與互斥問題。比如需要事務隔離場景、主從同步場景。
(3) 元數據鎖和Innodb鎖的區別:
- 元數據鎖主要關注數據庫對象的元信息,而InnoDB鎖主要關注數據的一致性和隔離性。
- MDL鎖還能實現其他粒度級別的鎖,比如:全局鎖、庫級別的鎖、表空間級別的鎖。這是InnoDB存儲引擎不能直接實現的。
(4) 鎖表的原理是數據庫使用獨占式鎖機制。鎖表發生在 insert、update、delete中。比如:A程序執行了對table_1的insert、update、delete,并還未commit時,B程序也對table_1進行insert、update、delete時會發生資鎖表。
2.Flink CDC為什么引起元數據鎖事故
筆者使用Flink場景是,利用Flink CDC同步數據,然后做匯總統計。
(1) MySQL CDC如何工作
- 在 CDC 過程中,Flink 需要定期讀取數據源的變化并進行處理。需要元數據鎖 確保在讀取元數據(例如數據庫表的結構信息)時,沒有其他并發的操作修改了這些元數據,從而保證 Flink 的元數據和實際數據的一致性。
- 啟動MySQL CDC源時,它將執行FLUSH TABLES WITH READ LOCK,獲取一個全局讀取鎖,防止其他會話對這些表進行寫操作,從而保證捕獲的數據的一致性和準確性。該鎖將阻止其他寫入操作。
- 然后,它讀取當前binlog位置以及數據庫和表的schema。
- 之后,將釋放全局讀取鎖。然后,它掃描數據庫表并從先前記錄的位置讀取binlog。
- 如果發生故障,任務將重新啟動。
(2) 元數據鎖原因
因為Flink CDC啟動時執行FLUSH TABLES WITH READ LOCK直接上讀取鎖,由于時間較長,此時有大量的insert、update、delete操作一直處于等待,導致Mysql Connection無法釋放。
正好此時,Flink CDC執行同步任務時,又出現了異常,然后任務重啟,重啟后是上鎖,結果出現了惡性循環。導致更多的的insert、update、delete操作處于等待,導致更多的Myql Connection無法釋放,直接Connection全部耗盡。
然后所有應用都拿不到Mysql Connection,所以系統徹底不可用了。
至于Nacos為什么會執行DELETE FROM config_info WHERE data_id='com.alibaba.nacos.testMasterDB'呢?查閱資料后發現,Nacos也是從Mysql獲取Connection的,當Mysql出現問題時,比如死鎖、Connection耗盡、CPU打滿時,都會執行這個SQL。