使用innodb_force_recovery解决MySQL崩溃无法重启问题
一背景
某一创业的朋友的主机因为磁盘阵列损坏机器crash,重启MySQL服务时报如下错误:
InnoDB:Readingtablespaceinformationfromthe.ibdfiles... InnoDB:Restoringpossiblehalf-writtendatapagesfromthedoublewrite InnoDB:buffer... InnoDB:Doingrecovery:scanneduptologsequencenumber9120034833 15012516:12:51InnoDB:Startinganapplybatchoflogrecordstothedatabase... InnoDB:Progressinpercents:567891011121314151617181920212223242526272829303132333435363738394015012516:12:51[ERROR]mysqldgotsignal11; Thiscouldbebecauseyouhitabug.Itisalsopossiblethatthisbinary oroneofthelibrariesitwaslinkedagainstiscorrupt,improperlybuilt, ormisconfigured.Thiserrorcanalsobecausedbymalfunctioninghardware. Toreportthisbug,seehttp://kb.askmonty.org/en/reporting-bugs Wewilltryourbesttoscrapeupsomeinfothatwillhopefullyhelp diagnosetheproblem,butsincewehavealreadycrashed, somethingisdefinitelywrongandthismayfail. Serverversion:5.5.37-MariaDB-log key_buffer_size=268435456 read_buffer_size=1048576 max_used_connections=0 max_threads=1002 thread_count=0 Itispossiblethatmysqldcoulduseupto key_buffer_size+(read_buffer_size+sort_buffer_size)*max_threads=2332093Kbytesofmemory 41Hopethat.
二分析
主要关注mysqldgotsignal11的问题,从日志内容分析来看,数据库在机器crash导致日志文件损坏,重启之后无法正常恢复,更无法正常对外提供服务。
三解决
因为日志已经损坏,这里采用非常规手段,首先修改innodb_force_recovery参数,使mysqld跳过恢复步骤,将mysqld启动,将数据导出来然后重建数据库。
innodb_force_recovery可以设置为1-6,大的数字包含前面所有数字的影响。
1.(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。
2.(SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行fullpurge操作,会导致crash。
3.(SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。
4.(SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。
5.(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。
6.(SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。
注意
a当设置参数值大于0后,可以对表进行select,create,drop操作,但insert,update或者delete这类操作是不允许的。
b当innodb_purge_threads和innodb_force_recovery一起设置会出现一种loop现象:
15012517:07:42InnoDB:Waitingforthebackgroundthreadstostart 15012517:07:43InnoDB:Waitingforthebackgroundthreadstostart 15012517:07:44InnoDB:Waitingforthebackgroundthreadstostart 15012517:07:45InnoDB:Waitingforthebackgroundthreadstostart 15012517:07:46InnoDB:Waitingforthebackgroundthreadstostart 15012517:07:47InnoDB:Waitingforthebackgroundthreadstostart
在my.cnf中修改以下两个参数
innodb_force_recovery=6 innodb_purge_thread=0
重启MySQL
15012517:10:47[Note]Crashrecoveryfinished. 15012517:10:47[Note]ServersocketcreatedonIP:'0.0.0.0'. 15012517:10:47[Note]EventScheduler:Loaded0events 15012517:10:47[Note]/vdata/webserver/mysql/bin/mysqld:readyforconnections. Version:'5.5.37-MariaDB-log'socket:'/tmp/mysql.sock'port:3306Sourcedistribution
立即对数据库做逻辑导出,完成之后将innodb_force_recovery设置为0,innodb_purge_thread=1,然后重建数据库。
另外MySQL版本5.5以及之前,当innodb_purge_threads=1,innodb_force_recovery>1的情况会出现上文提到的循环报warning问题(=1没有问题),
原因:
MySQL的源代码中显示 当innodb_purge_threads和innodb_force_recovery一起设置会出现loop循环
while(srv_shutdown_state==SRV_SHUTDOWN_NONE){ if(srv_thread_has_reserved_slot(SRV_MASTER)==ULINT_UNDEFINED ||(srv_n_purge_threads==1 &&srv_thread_has_reserved_slot(SRV_WORKER) ==ULINT_UNDEFINED)){ ut_print_timestamp(stderr); fprintf(stderr,"InnoDB:Waitingforthebackgroundthreadstostart\n"); os_thread_sleep(1000000); }else{ break; } }
所以当需要设置innodb_force_recovery>1的时候需要关闭innodb_purge_threads,设置为0(默认)。
四小结
MySQLcrash或者MySQL数据库服务器crash会导致各种各样的问题,比如主备之间的error1594(5.6版本开启crash-safe,会最大程度上避免error1594的问题,以后会写5.6新特性介绍该功能),error1236,日志损坏,数据文件损坏,等等,本案例只是其中的一种,细心从日志中找的相关错误提示,逐步解决即可。