天天看點

MySQL · 引擎新特性 · 可開關的InnoDB死鎖檢測

在資料庫系統中,死鎖問題幾乎是不可避免的,一般要麼是資源互相占用導緻,或者是系統内部的鎖更新(在innodb内尤其普遍),尤其是糟糕的未經審查的sql設計通常是導緻死鎖的元兇。在mysql innodb引擎中,死鎖的檢測是通過深度周遊進行的,每一個需要等待的行鎖請求都需要去檢測是否可能産生死鎖。

死鎖檢測是一個成熟的資料庫系統必不可少的功能,但是!如果我們的應用sql經過了充分合理的設計和驗證,能夠杜絕絕大部分死鎖場景,這樣的開銷是否是可以避免的呢?

一個典型的場景是秒殺,也就是大量更新落到同一行記錄上,此時大量請求同一個記錄的排他行鎖,導緻了很長的等待隊列,而死鎖檢測會去查詢整個隊列,而在整個過程中,一些全局資源(如lock_sys mutex)會被持有。為了避免檢測深度過長的問題,innodb預設的最大檢測深度為200,當超出時,會列印出死鎖資訊并結束死鎖檢測。

在阿裡秒殺的場景随處可見,事實上在2012年雙十一之前,我們修改mysql的第一個更新檔就是關閉死鎖檢測,代碼量很小,就那麼幾行代碼,帶來的效果還不錯。(當然這隻是我們優化秒殺高并發負載場景下的第一步,遠不能滿足這幾年的業務需求,後來我們進行了一系列的優化措施來改善mysql以滿足需求,我的同僚們在不同的場合都提到過,這裡我不展開說了)

在mysql5.7.15版本開始,以及mysql8.0.0版本,終于把這個特性加上了,增加了新的開關innodb_deadlock_detect來禁止死鎖檢測。

這裡簡單的測試下,mysql版本為8.0.0(在該版本剛釋出就把自己的5.7測試環境覆寫掉了,懶得重裝了..),使用sysbench,autocommit的單行更新

關鍵配置:

測試資料為tps(rt ms):

threads

turn on

turn off

16

8200(2.0ms)

8300(2.03ms)

32

7900(4.32ms)

8100(4.23ms)

64

7600(9.21ms)

7800(9.13ms)

128

4950(28.7ms)

7200(19.28ms)

256

1870 (147.8ms)

6145(48.8ms)

512

442 (1169ms)

4389(129.9ms)

1024

78 (16000ms)

3000(385ms)

從測試可以看到,低并發下基本上性能沒啥并發,而在高并發下,tps和rt則有明顯的改善。在該測試中,當達到1024個并發時,執行個體已經完全不可用了,但關閉死鎖檢測後,執行個體依然能夠提供3k的tps

需要注意的是,你必須謹慎的使用這個功能,最好在滿足幾個條件才應去嘗試:

你的業務需要確定死鎖極少

你的業務确實有這方面的需求,經過充分的測試并确實能獲得提升

如果非要開啟這個功能,當真的發生死鎖時,隻能到鎖等待逾時才能復原,是以記得調小<code>innodb_lock_wait_timeout</code>

繼續閱讀