遭遇 bug InnoDB: Failing assertion: page_get_n_recs(page) > 1

babyyellow發表於2017-01-13

昨晚遇到了一個mysql 的bug  : 

170112 22:26:06  InnoDB: Assertion failure in thread 139900811020032 in file /export/home/pb2/build/sb_0-2859905-1295553452.13/mysql
-5.5.9/storage/innobase/ibuf/ibuf0ibuf.c line 4147
InnoDB: Failing assertion: page_get_n_recs(page) > 1
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to 
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
170112 22:26:06 - mysqld got signal 6 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help diagnose
the problem, but since we have already crashed, something is definitely wrong
and this may fail.



資料庫自動重啟 做recovery 的時候陷入死迴圈. 無法啟動資料庫. 


關於這個bug  搜尋了一下網路 : 

一下資料轉自雲棲社群 


摘要: 我們知道,在MySQL5.5裡,insert buffer換了個說法,叫change buffer,能夠快取對二級索引的操作,直到將實際的page讀入bp時才進行合併,這在IO-bound並且表上有很多二級索引時,可以有效提升效能。 但存在一個蛋疼的bug,在5.5.31版本才被徹底f...
我們知道,在MySQL5.5裡,insert buffer換了個說法,叫change buffer,能夠快取對二級索引的操作,直到將實際的page讀入bp時才進行合併,這在IO-bound並且表上有很多二級索引時,可以有效提升效能。




但存在一個蛋疼的bug,在5.5.31版本才被徹底fix掉.如果你不幸碰到如下斷言錯誤crash,那麼恭喜你中招了:
                InnoDB: Failing assertion: page_get_n_recs(page) > 1






這個問題最初可以追溯到2012年1月份的中旬,春節前三四天,當時一個線上庫不幸觸發該bug,導致crash,並且無法重啟。 當時的處理方式是用innodb froce recovery起來,同時關掉innodb purge thread(另外一個bug,設定一個較大的innodb force recovery無法啟動mysqld),然後dump資料,重建庫..



比較早的關於該bug的討論見:, 但bug#61104並沒用完全修復該bug,只是將斷言移除了而已,這樣使用者可以把例項起來,執行一次DDL來重建表的二級索引



後來Percona的 在buglist上提出了該bug的導致的根本原因()在於刪除ibuf記錄和應用Ibuf記錄並不是原子的,也就是不在一個mtr中,那麼在不恰當的時間點掛掉,就可能導致無法crash recovery,實際上,即使我們將innodb_change_buffer設定inserts也不是安全的。。。。



再後來,這個bug被fix掉了,但我看了diff後,發現fix的不完整,DELETE的場景依然存在問題。於是俺在Facebook上吐槽了下,Percona的Valeriy Kravchuk很熱心的幫忙確認了..




主要涉及兩個函式




>ibuf_merge_or_delete_for_page,是對一個block上記錄進行change buffer合併的主要函式;




對於Purge操作,即IBUF_OP_DELETE型別:
先執行ibuf_delete後,會直接進行ibuf_btr_pcur_commit_specify_mtr,提交redo,然後再去刪除ibuf記錄(ibuf_delete_rec)




>ibuf_delete_rec,每完成一次change buffer記錄的合併,都會呼叫該函式去從Ibuf tree中將其刪除




在ibuf_delete_rec函式中,當進行btr_cur_optimistic_delete失敗後,會先去commit mitr(呼叫ibuf_btr_pcur_commit_specify_mtr),再去開啟新的mtr做btr_cur_pessimistic_delete








我們知道,Innodb是透過mtr寫入的redo日誌來做crash recovery的,如果我們在merge資料成功和刪除ibuf記錄之間crash掉,那麼就可能資料記錄被更新了,但ibuf記錄還沒被刪除,從而觸發前面提到的斷言失敗(在做ibuf_delete時,想刪除記錄,卻發現page上的記錄已經刪光了…)




也就是說,實際上對於所有的change buffer操作型別都可能存在問題,只是對於purge操作,機率更高點,因為它有兩個風險點








官方第一次fix,在MySQL5.5.29裡,修復了ibuf_delete_rec中存在的問題,方式是先標記刪除ibuf entry,再做悲觀刪除





官方第二次fix,在MySQL5.5.31裡,修復ibuf_merge_or_delete_for_page中存在的問題


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/133735/viewspace-2132378/,如需轉載,請註明出處,否則將追究法律責任。

相關文章