MySQL核心月報2014.11-MySQL· 5.7優化·MetadataLock子系統的優化
背景
引入MDL鎖的目的,最初是為了解決著名的bug#989,在MySQL 5.1及之前的版本,事務執行過程中並不維護涉及到的所有表的Metatdata 鎖,極易出現複製中斷,例如如下執行序列:
- Session 1: BEGIN;
- Session 1: INSERT INTO t1 VALUES (1);
- Session 2: Drop table t1; ——–SQL寫入BINLOG
- Session 1: COMMIT; —–事務寫入BINLOG
在備庫重放 binlog時,會先執行DROP TABLE,再INSERT資料,從而導致複製中斷。
在MySQL 5.5版本里,引入了MDL, 在事務過程中涉及到的所有表的MDL鎖,直到事務結束才釋放。這意味著上述序列的DROP TABLE 操作將被Session 1阻塞住直到其提交。
不過用過5.5的人都知道,MDL實在是個讓人討厭的東西,相信不少人肯定遇到過在使用mysqldump做邏輯備份時,由於需要執行FLUSH TABLES WITH READ LOCK (以下用FTWRL縮寫代替)來獲取全域性GLOBAL的MDL鎖,因此經常可以看到“wait for global read lock”之類的資訊。如果備庫存在大查詢,或者複製執行緒正在執行比較漫長的DDL,並且FTWRL被block住,那麼隨後的QUERY都會被block住,導致業務不可用引發故障。
為了解決這個問題,Facebook為MySQL增加新的介面替換掉FTWRL 只建立一個read view ,並返回與read view一致的binlog位點;另外Percona Server也實現了一種類似的辦法來繞過FTWRL,具體點選文件連線以及percona的部落格,不展開闡述。
MDL解決了bug#989,卻引入了一個新的熱點,所有的MDL鎖物件被維護在一個hash物件中;對於熱點,最正常的想法當然是對其進行分割槽來分散熱點,不過這也是Facebook的大神Mark Callaghan在report了bug#66473後才加入的,當時Mark觀察到MDL_map::mutex的鎖競爭非常高,進而推動官方改變。因此在MySQL 5.6.8及之後的版本中,引入了新引數metadata_locks_hash_instances來控制對mdl hash的分割槽數(Rev:4350);
不過故事還沒結束,後面的測試又發現雜湊函式有問題,類似somedb.someprefix1….somedb.someprefix8的hash key值相同,都被hash到同一個桶下面了,相當於hash分割槽沒生效。這屬於hash演算法的問題,喜歡考古的同學可以閱讀下bug#66473後面Dmitry Lenev的分析。
Mark進一步的測試發現Innodb的hash計算演算法比my_hash_sort_bin要更高效, Oracle的開發人員重開了個bug#68487來跟蹤該問題,並在MySQL5.6.15對hash key計算函式進行優化,包括fix 上面說的hash計算問題(Rev:5459),使用MurmurHash3演算法來計算mdl key的hash值。
MySQL 5.7 對MDL鎖的優化
在MySQL 5.7裡對MDL子系統做了更為徹底的優化。主要從以下幾點出發:
第一,儘管對MDL HASH進行了分割槽,但由於是以表名+庫名的方式作為key值進行分割槽,如果查詢或者DML都集中在同一張表上,就會hash到相同的分割槽,引起明顯的MDL HASH上的鎖競爭
針對這一點,引入了LOCK-FREE的HASH來儲存MDL_lock,LF_HASH無鎖演算法基於論文”Split-Ordered Lists: Lock-Free Extensible Hash Tables”,實現還比較複雜。 注:實際上LF_HASH很早就被應用於Performance Schema,算是比較成熟的程式碼模組。
由於引入了LF_HASH,MDL HASH分割槽特性自然直接被廢除了 。
第二,從廣泛使用的實際場景來看,DML/SELECT相比DDL等高階別MDL鎖型別,是更為普遍的,因此可以針對性的降低DML和SELECT操作的MDL開銷。
為了實現對DML/SELECT的快速加鎖,使用了類似LOCK-WORD的加鎖方式,稱之為FAST-PATH,如果FAST-PATH加鎖失敗,則走SLOW-PATH來進行加鎖。
每個MDL鎖物件(MDL_lock)都維持了一個long long型別的狀態值來標示當前的加鎖狀態,變數名為MDL_lock::m_fast_path_state 舉個簡單的例子:(初始在sbtest1表上對應MDL_lock::m_fast_path_state值為0)
- Session 1: BEGIN;
- Session 1: SELECT * FROM sbtest1 WHERE id =1; //m_fast_path_state = 1048576, MDL ticket 不加MDL_lock::m_granted佇列
- Session 2: BEGIN;
- Session 2: SELECT * FROM sbtest1 WHERE id =2; //m_fast_path_state=1048576+1048576=2097152,同上,走FAST PATH
- Session 3: ALTER TABLE sbtest1 ENGINE = INNODB; //DDL請求加的MDL_SHARED_UPGRADABLE型別鎖被視為unobtrusive lock,可以認為這個是比上述SQL的MDL鎖級別更高的鎖,並且不相容,因此被強制走slow path。而slow path是需要加MDL_lock::m_rwlock的寫鎖。m_fast_path_state = m_fast_path_state | MDL_lock::HAS_SLOW_PATH | MDL_lock::HAS_OBTRUSIVE
- 注:DDL還會獲得庫級別的意向排他MDL鎖或者表級別的共享可升級鎖,但為了表述方便,這裡直接忽略了,只考慮涉及的同一個MDL_lock鎖物件。
- Session 4: SELECT * FROM sbtest1 WHERE id =3; // 檢查m_fast_path_state &HAS_OBTRUSIVE,如果DDL還沒跑完,就會走slow path。
從上面的描述可以看出,MDL子系統顯式的對鎖型別進行了區分(OBTRUSIVE or UNOBTRUSIVE),儲存在陣列矩陣m_unobtrusive_lock_increment。 因此對於相容型別的MDL鎖型別,例如DML/SELECT,加鎖操作幾乎沒有任何讀寫鎖或MUTEX開銷。
對應WL#7304, WL#7306 , PATCH(Rev:7067,Rev:7129)(Rev:7586)
第三,由於引入了MDL鎖,實際上早期版本用於控制Server和引擎層表級併發的THR_LOCK 對於Innodb而言已經有些冗餘了,因此Innodb表完全可以忽略這部分的開銷。
不過在已有的邏輯中,Innodb依然依賴THR_LOCK來實現LOCK TABLE tbname READ,因此增加了新的MDL鎖型別來代替這種實現。
實際上程式碼的大部分修改都是為了處理新的MDL型別,Innodb的改動只有幾行程式碼。
第四,Server層的使用者鎖(通過GET_LOCK函式獲取)使用MDL來重新實現。
使用者可以通過GET_LOCK()來同時獲取多個使用者鎖,同時由於使用MDL來實現,可以藉助MDL子系統實現死鎖的檢測。
注意由於該變化,導致使用者鎖的命名必須小於64位元組,這是受MDL子系統的限制導致。
相關文章
- MySQL 5.7 索引優化MySql索引優化
- (mysql優化-3) 系統優化MySql優化
- MySQL核心月報2014.11-MySQL· 5.7特性·高可用支援MySql
- MySQL 5.7 ORDER BY排序的優化MySql排序優化
- MySQL核心月報2014.11-MySQL· 5.7改進·Recovery改進MySql
- MySQL優化之系統變數優化MySql優化變數
- MySQL 5.7 跟蹤優化器MySql優化
- MySQL 核心深度優化MySql優化
- MySQL 5.7資料庫引數優化MySql資料庫優化
- MySQL子查詢的優化薦MySql優化
- Mysql優化系列之——優化器對子查詢的處理MySql優化
- MySQL核心月報2014.12-MySQL· 效能優化·threadpool原理分析MySql優化thread
- Linux 效能優化之 IO 子系統Linux優化
- 系統優化報告表格樣例優化
- 系統的優化思路優化
- Linux優化之IO子系統監控與調優Linux優化
- mysql的優化MySql優化
- MySQL 5.7 優化不能只看執行計劃MySql優化
- 系統優化怎麼做-Tomcat優化優化Tomcat
- oracle效能優化二——作業系統優化Oracle優化作業系統
- Linux系統優化部分核心引數調優中文註釋Linux優化
- MySQL 效能優化之索引優化MySql優化索引
- MySQL優化-安裝配置優化MySql優化
- MySQL 效能優化之SQL優化MySql優化
- MySQL優化(1)——–常用的優化步驟MySql優化
- mysql優化MySql優化
- Mysql 優化MySql優化
- mysql子查詢的缺陷以及5.6的優化MySql優化
- mysql之 CentOS系統針對mysql引數優化MySqlCentOS優化
- mysql的sql優化MySql優化
- Linux 系統優化Linux優化
- 系統優化相關優化
- MySQL效能結構優化原理(技術核心)MySql優化
- 【效能優化】秒殺系統效能優化初體驗優化
- MySQl 配置InnoDB持久化的優化器統計資訊MySql持久化優化
- mysql效能優化MySql優化
- MySQL優化面試MySql優化面試
- mysql優化(一)MySql優化