Latch致使MySQL Crash

做者:沃趣科技數據庫專家 董紅禹

問題概述數據庫

最近咱們遇到一個MySQL的問題,分析後頗有表明意義,特意寫出來供你們參考。出現問題是,數據庫先是被置爲只讀,而後過了一段時間,MySQL直接Crash掉了,發生Crash時MySQL的error日誌中打印瞭如下內容:緩存

根據日誌中咱們能夠看到,線程140363572082432要對記錄上一個X鎖,可是等待0x7fa949340740線程的RW-Latch的釋放。markdown

咱們再向下看查詢到以下信息(涉及到用戶信息 謂詞就用xxx代替):併發

根據上面信息咱們去數據庫中查看了這些select語句,發現執行計劃都是全表掃描。首先數據庫變成了只讀,最後數據庫Crash了,Crash輸出的信息以下:函數

InnoDB: Error: semaphore wait has lasted > 600 seconds 提示600秒沒有響應 數據庫選擇了Crash 強制重啓。從報錯信息來看:線程

1,update語句須要在記錄上面加X鎖,可是必須等待RW-Latch的釋放日誌

2,因爲有大量的select語句是全表掃描,一直佔用Latch沒有釋放,update遲遲競爭不到RW-latchblog

3,Innodb 的Diagnostic線程檢查到RW-Latch等待超過了600秒尚未返回,認爲系統出現了嚴重問題,因而觸發了MySQL服務的Crash。索引

 

進一步分析內存

這裏首先須要補充一下Latch的概念:Latch在MySQL中是用於保護高速緩衝區中共享數據的.

舉個例子:

當咱們執行select時,數據是緩存在buffer pool中的,多個線程併發訪問或者修改這個數據必然須要一個併發控制機制,這個就是Latch

你們知道,數據庫要訪問的數據都必須先存在緩存中,而緩存通常比磁盤空間要小,數據緩存使用hash表來記錄數據頁是否在內存中。在Oracle中的併發控制比較精細:首先會對hash桶加latch,並根據hash桶查找對應的數據並加上pin,而後釋放Latch。而MySQL相對沒有控制得這麼精細,對應的RW-Latch在errlog中說的很清楚,該RW-Latch是在buf0buf.cc的1069行建立的 RW-latch at 0x7fa949340740 created in file buf0buf.cc line 1069

對應的代碼摘錄以下:

跟蹤源碼,知道這個Latch是MySQL在數據庫啓動,初始化 innodb_buffer_pool時,將Latch建立好的。對應的函數調用過程:

正是因爲這個RW-Latch被長時間佔用了,其餘的線程一直競爭不到,才致使了這個問題。

 

修復建議

這類問題的發生多數都是由於SQL寫的很差,在表上面進行了大量的全表掃描佔用了大量的Latch,解決方案就是避免SQL長時間佔用Latch:

1,修改select查詢避免全表掃描,避免Latch長期被佔用。

2,適當的加索引,讓select執行更快,也避免一個select鎖的數據更少。

3,適當加大buffer pool instance,每一個buffer pool都有本身獨立的Latch,避免latch競爭。

相關文章
相關標籤/搜索