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

本文详细解析了一个出现在MySQL 5.5版本中InnoDB存储引擎的严重bug,该bug与Change Buffer机制有关,会导致数据库崩溃且无法正常重启。文章探讨了bug的根本原因,以及MySQL官方如何逐步修复此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


昨晚遇到了一个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.



数据库自动重启 做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的讨论见:http://bugs.mysql.com/bug.php?id=61104, 但bug#61104并没用完全修复该bug,只是将断言移除了而已,这样用户可以把实例起来,执行一次DDL来重建表的二级索引



后来Percona的Alexey Kopytov 在buglist上提出了该bug的导致的根本原因(http://bugs.mysql.com/bug.php?id=66819)在于删除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,再做悲观删除
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

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/133735/viewspace-2132378/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/133735/viewspace-2132378/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值