一次MySQL(INNODB儲存引擎) 死鎖捉蟲記

2022-02-26 12:50:43 字數 1953 閱讀 1636

前言

任何系統不管在什麼階段都需要關注生產環境錯誤日誌,最近幾個月內,發現偶爾會出現資料庫死鎖情況。以前碰到的資料庫類錯誤大部分是sql語法造成的錯誤,來到新東家之後才第一次碰到死鎖情況,以前是搞遊戲開發,現在是搞電商類開發,可能是不同的專案不同的業務的原因吧,查閱了各種資料後發現,是我想錯了:(。一般業務瓶頸在資料庫層,對於資料庫層的問題需要重點關注,以為死鎖這種情況是很嚴重的問題,這個要分情況,偶爾死鎖對業務不會有太大的影響,我又想錯了:(。

蟲子發現

第一次發現死鎖很驚訝,這個是什麼鬼?不知道是什麼原因?不知道怎麼解決?不知道會不會影響業務?沒有搞清楚這個問題,生怕是業務的定時炸彈,每天心裡不踏實。蟲子發現如下:

死鎖

對資料庫記錄操作之前,當前執行緒需要先請求獲得相關鎖,獲得鎖之後才會執行sql語句。鎖根據粒度分為表鎖和行鎖(不是所有儲存引擎都支援行鎖),鎖根據型別分為排他鎖和共享鎖(不同的操作需要獲得的鎖型別不同,不同的鎖型別行為也不相同)。資源越少,出現死鎖的概率會更小,比如只支援表鎖的儲存引擎會比支援行鎖的儲存引擎出現的概率更小。

併發事務出現時,當出現多個事務間彼此等待對方資源釋放,事務因沒有處理完,已經獲得鎖的資源不會釋放,大家彼此這樣等待著僵持著,這樣會一直下去,死鎖就這樣產生了。

死鎖現象關係型資料庫無法避免,不是mysql 資料庫獨有。mysql 資料庫會自動檢查死鎖情況,當發現時,會回滾更簡單的事務並返回給執行緒乙個錯誤。怎麼判斷哪個事務更簡單呢,根據事務影響的紀錄行數判斷,紀錄行數越小被認為更簡單。

診斷分析

當出現死鎖時,為了解決這個問題,需要診斷分析當時出現死鎖的上下文資訊以及相關的執行語句,這樣才能知道怎麼避免。mysql 資料庫只儲存最近一次的死鎖事務,如果同時有超過2個事務出現死鎖,至多只儲存2個事務資訊。執行mysql 客戶端命令:show engine innodb status獲得最近一次事務死鎖相關資訊。如果是mysql 5.6之後的版本,可以開啟全域性變數innodb_print_all_deadlocks=on,這樣死鎖相關資訊會儲存到mysql 錯誤日誌中。如果是不支援這個變數的版本,可以採用定時執行客戶端命令採集死鎖資訊,然後儲存到日誌檔案中,每個事務都有唯一編號,可以根據這個去重。當死鎖頻繁出現時,需要引起注意;當偶爾出現時,可以不用關注。死鎖資訊格式如下,不同mysql 版本內容會有點差異,相關說明可以檢視參考資料一。

預防措施

知道死鎖為何物,以及通過分析診斷日誌資訊,就可以對症下藥了,但是有一些通用的基本原則可以遵守:

1 盡可能保持事務簡單以及快速執行;

2 盡可能保持事務影響行數少以及涉及的相關表少;

3 避免使用外來鍵約束,其實大部分應用允許資料冗餘的;

4 影響行數大的事務盡量使用相同的排序過濾;

5 資料庫併發不高的業務,可以通過某種方式順序執行語句,一次只執行乙個,通過查資料知道一種實現方式:建立乙個表,這個表始終只有一條紀錄,各個事務通過爭奪這個鎖來實現線性執行,感覺這個應該沒啥用:(;

6 有些場景死鎖會檢查不到,設定鎖的過期時間就很重要了,mysql可以通過設定選項innodb_lock_wait_timeout;

危害程度

鎖資源得不到及時釋放,會影響資料庫併發處理,如果經常出現死鎖,需要及時採取措施處理,如果只是偶爾出現,業務邏輯捕捉到死鎖錯誤可以採取重試執行事務,對業務不會有什麼影響,總之具體問題需要具體分析:)

後記

參考資料

how to deal with mysql deadlocks

deadlock

deadlock detection and rollback

how to cope with deadlocks

mysql InnoDB儲存引擎

innodb的組成部分 1.後台執行緒 2.儲存引擎記憶體池 innodb儲存引擎記憶體緩衝池 1.記憶體緩衝池 innodb是基於磁碟儲存的,並將其中的記錄按照頁的方式進行管理。因此,可將其視為基礎磁碟的資料庫系統。在資料庫系統中,由於cpu速度與磁碟速度之間的紅狗,基於磁碟的資料庫系統通常使用緩...

MySQL InnoDB 儲存結構

mysql innodb 儲存結構 innodb儲存引擎的關鍵特性包括 插入緩衝 insert buffer 兩次寫 double write 自適應雜湊索引 adaptive hash index 非同步io async io 重新整理鄰接頁 從邏輯上講 所有的資料都被邏輯的放在乙個空間中,稱為t...

Mysql Innodb儲存引擎

鎖 參考資料 參考資料 行鎖 innodb的鎖是對索引加鎖,如果查詢到並沒有用到索引就會對錶進行加鎖 record lock 對單條記錄加上鎖 gap lock 間隙鎖,鎖定乙個範圍,但是不包含記錄本身 next key lock record lock gap lock,鎖定乙個方位並鎖定記錄本身...