昨晚遇到了一個(gè)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 http://bugs.mysql.com. 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. 數(shù)據(jù)庫自動(dòng)重啟 做recovery 的時(shí)候陷入死循環(huán). 無法啟動(dòng)數(shù)據(jù)庫. 關(guān)于這個(gè)bug 搜索了一下網(wǎng)絡(luò) : 一下數(shù)據(jù)轉(zhuǎn)自云棲社區(qū) 摘要: 我們知道,在MySQL5.5里,insert buffer換了個(gè)說法,叫change buffer,能夠緩存對(duì)二級(jí)索引的操作,直到將實(shí)際的page讀入bp時(shí)才進(jìn)行合并,這在IO-bound并且表上有很多二級(jí)索引時(shí),可以有效提升性能。 但存在一個(gè)蛋疼的bug,在5.5.31版本才被徹底f... 我們知道,在MySQL5.5里,insert buffer換了個(gè)說法,叫change buffer,能夠緩存對(duì)二級(jí)索引的操作,直到將實(shí)際的page讀入bp時(shí)才進(jìn)行合并,這在IO-bound并且表上有很多二級(jí)索引時(shí),可以有效提升性能。 但存在一個(gè)蛋疼的bug,在5.5.31版本才被徹底fix掉.如果你不幸碰到如下斷言錯(cuò)誤crash,那么恭喜你中招了: InnoDB: Failing assertion: page_get_n_recs(page) > 1 這個(gè)問題最初可以追溯到2012年1月份的中旬,春節(jié)前三四天,當(dāng)時(shí)一個(gè)線上庫不幸觸發(fā)該bug,導(dǎo)致crash,并且無法重啟。 當(dāng)時(shí)的處理方式是用innodb froce recovery起來,同時(shí)關(guān)掉innodb purge thread(另外一個(gè)bug,設(shè)置一個(gè)較大的innodb force recovery無法啟動(dòng)mysqld),然后dump數(shù)據(jù),重建庫.. 比較早的關(guān)于該bug的討論見:http://bugs.mysql.com/bug.php?id=61104, 但bug#61104并沒用完全修復(fù)該bug,只是將斷言移除了而已,這樣用戶可以把實(shí)例起來,執(zhí)行一次DDL來重建表的二級(jí)索引 后來Percona的Alexey Kopytov 在buglist上提出了該bug的導(dǎo)致的根本原因(http://bugs.mysql.com/bug.php?id=66819)在于刪除ibuf記錄和應(yīng)用Ibuf記錄并不是原子的,也就是不在一個(gè)mtr中,那么在不恰當(dāng)?shù)臅r(shí)間點(diǎn)掛掉,就可能導(dǎo)致無法crash recovery,實(shí)際上,即使我們將innodb_change_buffer設(shè)置inserts也不是安全的。。。。 再后來,這個(gè)bug被fix掉了,但我看了diff后,發(fā)現(xiàn)fix的不完整,DELETE的場(chǎng)景依然存在問題。于是俺在Facebook上吐槽了下,Percona的Valeriy Kravchuk很熱心的幫忙確認(rèn)了.. 主要涉及兩個(gè)函數(shù) >ibuf_merge_or_delete_for_page,是對(duì)一個(gè)block上記錄進(jìn)行change buffer合并的主要函數(shù); 對(duì)于Purge操作,即IBUF_OP_DELETE類型: 先執(zhí)行ibuf_delete后,會(huì)直接進(jìn)行ibuf_btr_pcur_commit_specify_mtr,提交redo,然后再去刪除ibuf記錄(ibuf_delete_rec) >ibuf_delete_rec,每完成一次change buffer記錄的合并,都會(huì)調(diào)用該函數(shù)去從Ibuf tree中將其刪除 在ibuf_delete_rec函數(shù)中,當(dāng)進(jìn)行btr_cur_optimistic_delete失敗后,會(huì)先去commit mitr(調(diào)用ibuf_btr_pcur_commit_specify_mtr),再去開啟新的mtr做btr_cur_pessimistic_delete 我們知道,Innodb是通過mtr寫入的redo日志來做crash recovery的,如果我們?cè)趍erge數(shù)據(jù)成功和刪除ibuf記錄之間crash掉,那么就可能數(shù)據(jù)記錄被更新了,但ibuf記錄還沒被刪除,從而觸發(fā)前面提到的斷言失?。ㄔ谧鰅buf_delete時(shí),想刪除記錄,卻發(fā)現(xiàn)page上的記錄已經(jīng)刪光了…) 也就是說,實(shí)際上對(duì)于所有的change buffer操作類型都可能存在問題,只是對(duì)于purge操作,概率更高點(diǎn),因?yàn)樗袃蓚€(gè)風(fēng)險(xiǎn)點(diǎn) 官方第一次fix,在MySQL5.5.29里,修復(fù)了ibuf_delete_rec中存在的問題,方式是先標(biāo)記刪除ibuf entry,再做悲觀刪除 http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/3979 官方第二次fix,在MySQL5.5.31里,修復(fù)ibuf_merge_or_delete_for_page中存在的問題 http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4177 |