天天看點

MySQL · 捉蟲動态 · 備庫1206錯誤問題說明

一個使用者自建mysql,出現備庫複制中斷的問題,報錯為slave sql thread 錯誤,the total number of locks exceeds the lock table size。

這個報錯在代碼中的抛錯邏輯為:

文字解釋是:如果buffer pool中的空閑頁面和lru頁面總和少于buffer pool 大小的1/4,則認為記憶體不夠用,報錯。

buffer pool 哪裡去了

buffer pool是innodb内部管理記憶體的統一結構。預設每個page 16k。初始化後,每個page都是空閑狀态,放在free中。

當讀取資料等需要用到頁面資料的操作時,将資料從磁盤讀取到記憶體中,用的就是buffer pool的page。為了支援淘汰機制,innodb内部維護了一個淘汰連結清單,就是lru list。裝了資料的page被從free list移到lru list。

但是,除了正常的讀取資料,還有其他的邏輯需要從buffer pool中“搶”資源。比如本例中是因為undo page。

事務越大,需要的undo page越多,在整個事務未送出前,undo page是必須強占記憶體的。這就可能導緻一種情況:事務過大,導緻buffer pool全部被用光,無法提供正常服務。

是以innodb有了上面的保護機制。觸發這個上限後報錯後,事務會復原,釋放undo page。

為什麼主庫執行成功備庫失敗了

從上面的分析和代碼中可以看到,判斷記憶體是否占用過多,設定的上限是buffer_pool size的1/4.

另外,5.6以後支援了設定多個 innodb_buffer_pool_instances,也就是分成多個pool, 在現在的邏輯中,認為隻要“任意一個pool滿足上述超過1/4的條件”,都判定為記憶體消耗過限。

是以主要排查參數:

備庫的 innodb_buffer_pool_size 是否小于主庫值

若主備的innodb_buffer_pool_size值相同,備庫的 innodb_buffer_pool_instances 值是否更大。

作為驗證

dba在發現備庫apply error的時候第一步往往是用 mysqlbinlog 工具去看導緻錯誤的event是什麼。這時候會發現其實是一個批量的load資料,或者update/delete大事務導緻。

buffer pool不僅用于緩存page,會有其他資料結構争搶;

主備的參數盡量保持一緻;

盡量避免超大事務,即使不考慮備庫apply error。這種超大事務在主庫執行,由于undo page占用buffer pool,可能會導緻buffer pool命中率突然下降,影響業務。

繼續閱讀