遭遇 bug InnoDB: Failing assertion: page_get_n_recs(page) > 1[ mysql数据库 ]
mysql数据库
时间:2024-12-03 12:12:13
作者:文/会员上传
简介:
昨晚遇到了一个mysql的bug:17011222:26:06InnoDB:Assertionfailureinthread139900811020032infile/export/home/pb2/build/sb_0-2859905-1295553452.13/mysql-5.5.9/storage
以下为本文的正文内容,内容仅供参考!本站为公益性网站,复制本文以及下载DOC文档全部免费。
昨晚遇到了一个mysql的bug:
17011222:26:06InnoDB:Assertionfailureinthread139900811020032infile/export/home/pb2/build/sb_0-2859905-1295553452.13/mysql
-5.5.9/storage/innobase/ibuf/ibuf0ibuf.cline4147
InnoDB:Failingassertion:page_get_n_recs(page)>1
InnoDB:Weintentionallygenerateamemorytrap.
InnoDB:Submitadetailedbugreporttohttp://bugs.mysql.com.
InnoDB:Ifyougetrepeatedassertionfailuresorcrashes,even
InnoDB:immediatelyafterthemysqldstartup,theremaybe
InnoDB:corruptionintheInnoDBtablespace.Pleasereferto
InnoDB:http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB:aboutforcingrecovery.
17011222:26:06-mysqldgotsignal6;
Thiscouldbebecauseyouhitabug.Itisalsopossiblethatthisbinary
oroneofthelibrariesitwaslinkedagainstiscorrupt,improperlybuilt,
ormisconfigured.Thiserrorcanalsobecausedbymalfunctioninghardware.
Wewilltryourbesttoscrapeupsomeinfothatwillhopefullyhelpdiagnose
theproblem,butsincewehavealreadycrashed,somethingisdefinitelywrong
andthismayfail.
数据库自动重启做recovery的时候陷入死循环.无法启动数据库.
关于这个bug搜索了一下网络:
一下数据转自云栖社区
摘要:我们知道,在MySQL5.5里,insertbuffer换了个说法,叫changebuffer,能够缓存对二级索引的操作,直到将实际的page读入bp时才进行合并,这在IO-bound并且表上有很多二级索引时,可以有效提升性能。但存在一个蛋疼的bug,在5.5.31版本才被彻底f...
我们知道,在MySQL5.5里,insertbuffer换了个说法,叫changebuffer,能够缓存对二级索引的操作,直到将实际的page读入bp时才进行合并,这在IO-bound并且表上有很多二级索引时,可以有效提升性能。
但存在一个蛋疼的bug,在5.5.31版本才被彻底fix掉.如果你不幸碰到如下断言错误crash,那么恭喜你中招了:
InnoDB:Failingassertion:page_get_n_recs(page)>1
这个问题最初可以追溯到2012年1月份的中旬,春节前三四天,当时一个线上库不幸触发该bug,导致crash,并且无法重启。当时的处理方式是用innodbfrocerecovery起来,同时关掉innodbpurgethread(另外一个bug,设置一个较大的innodbforcerecovery无法启动mysqld),然后dump数据,重建库..
比较早的关于该bug的讨论见:http://bugs.mysql.com/bug.php?id=61104,但bug#61104并没用完全修复该bug,只是将断言移除了而已,这样用户可以把实例起来,执行一次DDL来重建表的二级索引
后来Percona的AlexeyKopytov在buglist上提出了该bug的导致的根本原因(http://bugs.mysql.com/bug.php?id=66819)在于删除ibuf记录和应用Ibuf记录并不是原子的,也就是不在一个mtr中,那么在不恰当的时间点挂掉,就可能导致无法crashrecovery,实际上,即使我们将innodb_change_buffer设置inserts也不是安全的。。。。
再后来,这个bug被fix掉了,但我看了diff后,发现fix的不完整,DELETE的场景依然存在问题。于是俺在Facebook上吐槽了下,Percona的ValeriyKravchuk很热心的帮忙确认了..
主要涉及两个函数
>ibuf_merge_or_delete_for_page,是对一个block上记录进行changebuffer合并的主要函数;
对于Purge操作,即IBUF_OP_DELETE类型:
先执行ibuf_delete后,会直接进行ibuf_btr_pcur_commit_specify_mtr,提交redo,然后再去删除ibuf记录(ibuf_delete_rec)
>ibuf_delete_rec,每完成一次changebuffer记录的合并,都会调用该函数去从Ibuftree中将其删除
在ibuf_delete_rec函数中,当进行btr_cur_optimistic_delete失败后,会先去commitmitr(调用ibuf_btr_pcur_commit_specify_mtr),再去开启新的mtr做btr_cur_pessimistic_delete
我们知道,Innodb是通过mtr写入的redo日志来做crashrecovery的,如果我们在merge数据成功和删除ibuf记录之间crash掉,那么就可能数据记录被更新了,但ibuf记录还没被删除,从而触发前面提到的断言失败(在做ibuf_delete时,想删除记录,却发现page上的记录已经删光了…)
也就是说,实际上对于所有的changebuffer操作类型都可能存在问题,只是对于purge操作,概率更高点,因为它有两个风险点
官方第一次fix,在MySQL5.5.29里,修复了ibuf_delete_rec中存在的问题,方式是先标记删除ibufentry,再做悲观删除
http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/3979
官方第二次fix,在MySQL5.5.31里,修复ibuf_merge_or_delete_for_page中存在的问题
http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4177
展开阅读全文 ∨