现象


经过一个五一小长假,电脑也得到了很好的休息。

开工第一天,发现Mysql挂掉了,原因是其他服务产生了大量日志,把磁盘搞满了。

理论上,磁盘满了,删除点文件,把空间释放出来,再重启Mysql就好了。

但这次,重启不了了,查看状态显示如下:

定位解决


重启了几次,查看状态时,都是报这个错误。

下面看一下Mysql的日志吧:

这里的信息比较详细,可以看出Mysql在几天前已经挂掉了,它把丢弃无法恢复的数据。

好在它给出了解决方法:set innodb_force_recovery=1

于是,修改配置文件,vim /etc/myf,在最后增加一行:innodb_force_recovery=1。

重启Mysql:

ok,启动正常,但业务报错,继续查看Mysql日志:

唂,把innodb_force_recovery设置为1后,Mysql不允许修改数据了,需要把它设置为0.

按照提示,vim /etc/myf,修改innodb_force_recovery=0,重启Mysql:

ok了,业务也正常了。

关于innodb_force_recovery


Mysql的innodb_force_recovery,说明如下:

这个参数一般是不会用到的。他是当mysql crash后,导致数据库表空间损坏,或者其他原因导致innodb事务日志损坏等原因导致mysql 闪退后无法正常启动。

这个参数的默认值是0, 如果面临上述问题,无法正常启动mysql,并且查看mysql错误日志发现导致mysql无法启动的原因是innodb的问题,那么就需要设置这个参数了。

它的取值范围是0-6,含义如下:

  • 1:(SRV_FORCE_IGNORE_CORRUPT): 忽略检查到的 corrupt 页。尽管检测到了损坏的 page 仍强制服务运行。一般设置为该值即可,然后 dump 出库表进行重建。
  • 2:(SRV_FORCE_NO_BACKGROUND): 阻止主线程的运行,如主线程需要执行 full purge 操作,会导致 crash。 阻止 master thread 和任何 purge thread 运行。若 crash 发生在 purge 环节则使用该值。
  • 3:(SRV_FORCE_NO_TRX_UNDO): 不执行事务回滚操作。
  • 4:(SRV_FORCE_NO_IBUF_MERGE): 不执行插入缓冲的合并操作。如果可能导致崩溃则不要做这些操作。不要进行统计操作。该值可能永久损坏数据文件。若使用了该值,则将来要删除和重建辅助索引。
  • 5:(SRV_FORCE_NO_UNDO_LOG_SCAN): 不查看重做日志,InnoDB 存储引擎会将未提交的事务视为已提交。此时 InnoDB 甚至把未完成的事务按照提交处理。该值可能永久性的损坏数据文件。
  • 6:(SRV_FORCE_NO_LOG_REDO): 不执行前滚的操作。恢复时不做 redo log roll-forward。使数据库页处于废止状态,继而可能引起 B 树或者其他数据库结构更多的损坏。

使用参数innodb_force_recovery建议:

  • 如果MySQL服务故障重启后,因为事务回滚导致异常,可以将参数innodb_force_recovery设置为3跳过回滚阶段
  • 如果因为MySQL数据页损坏导致异常,可以使用SELECT+WHERE查找出未损坏数据并将其通过mysqldump导出。
  • 将innodb_force_recovery参数设置大于0启动服务后,应通过修改端口或域名(VIP)指向来屏蔽应用访问。
  • 将innodb_force_recovery参数设置大于0启动服务后,可以通过mysqlcheck命令来对表进行检查/分析/优化/修复。
  • 使用force_recovery重启服务前,建议对数据库所有文件进行备份,避免修复过程中对数据进行二次损害。

小结


Mysql应用广泛,但要想做到高可用,还是要好好思考一下的。

但Mysql崩溃后也不要慌乱,查看日志是解决问题的第一步,它的日志记录的还是非常完善的。

参考资料

MySQL–使用innodb_force_recovery修复数据库异常

更多推荐

Mysql历险记: Job for mysqld.service failed because the control process exited with