机房断电、MySQL启动失败,InnoDB数据损坏如何恢复

您所在的位置:网站首页 电脑日志文件损坏导致电脑打不开 机房断电、MySQL启动失败,InnoDB数据损坏如何恢复

机房断电、MySQL启动失败,InnoDB数据损坏如何恢复

2023-09-09 07:58| 来源: 网络整理| 查看: 265

概要

【问题原因】服务器突然断电 【故障报告】数据库表结构损坏 【解决思路】进入强制恢复模式,库表及数据重建

故障发现

周末园区断电,周一启动数据库就直接报错了:

ERROR! The server quit without updating PID file (/var/lib/mysql/localhost.mobile.pid).

此时的心情 干(chui)劲(tou)满(sang)满(qi)的去查看错误日志,尝试定位原因:

160822 12:57:35 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql 2016-08-22 12:57:35 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). 2016-08-22 12:57:35 0 [Note] /usr/sbin/mysqld (mysqld 5.6.25) starting as process 8966 ... 2016-08-22 12:57:35 8966 [Warning] Buffered warning: Changed limits: max_open_files: 1024 (requested 5000) 2016-08-22 12:57:35 8966 [Warning] Buffered warning: Changed limits: max_connections: 214 (requested 800) 2016-08-22 12:57:35 8966 [Note] Plugin 'FEDERATED' is disabled. 2016-08-22 12:57:35 8966 [Note] InnoDB: Using atomics to ref count buffer pool pages 2016-08-22 12:57:35 8966 [Note] InnoDB: The InnoDB memory heap is disabled 2016-08-22 12:57:35 8966 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 2016-08-22 12:57:35 8966 [Note] InnoDB: Memory barrier is not used 2016-08-22 12:57:35 8966 [Note] InnoDB: Compressed tables use zlib 1.2.3 2016-08-22 12:57:35 8966 [Note] InnoDB: Using Linux native AIO 2016-08-22 12:57:35 8966 [Note] InnoDB: Using CPU crc32 instructions 2016-08-22 12:57:35 8966 [Note] InnoDB: Initializing buffer pool, size = 128.0M 2016-08-22 12:57:35 8966 [Note] InnoDB: Completed initialization of buffer pool 2016-08-22 12:57:35 8966 [Note] InnoDB: Highest supported file format is Barracuda. ======================== 打入日志内部的奸细,提醒重点 ======================== --- 2016-08-22 12:57:35 8966 [Note] InnoDB: The log sequence numbers 583029738 and 583029738 in ibdata files do not match the log sequence number 587038442 in the ib_logfiles! 2016-08-22 12:57:35 8966 [Note] InnoDB: Database was not shutdown normally! 2016-08-22 12:57:35 8966 [Note] InnoDB: Starting crash recovery. 2016-08-22 12:57:35 8966 [Note] InnoDB: Reading tablespace information from the .ibd files... 2016-08-22 12:57:35 8966 [ERROR] InnoDB: Attempted to open a previously opened tablespace. Previous tablespace mysql/slave_master_info uses space ID: 4 at filepath: ./mysql/slave_master_info.ibd. Cannot open tablespace acc/ac_acc_link_11 which uses space ID: 4 at filepath: ./acc/ac_acc_link_11.ibd --- 2016-08-22 12:57:35 7f2a6cfcf720 InnoDB: Operating system error number 2 in a file operation. InnoDB: The error means the system cannot find the path specified. InnoDB: If you are installing InnoDB, remember that you must create InnoDB: directories yourself, InnoDB does not create them. ======================== 打入日志内部的奸细,提醒重点 ======================== --- InnoDB: Error: could not open single-table tablespace file ./acc/ac_acc_link_11.ibd InnoDB: We do not continue the crash recovery, because the table may become InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it. InnoDB: To fix the problem and start mysqld: --- InnoDB: 1) If there is a permission problem in the file and mysqld cannot InnoDB: open the file, you should modify the permissions. InnoDB: 2) If the table is not needed, or you can restore it from a backup, InnoDB: then you can remove the .ibd file, and InnoDB will do a normal InnoDB: crash recovery and ignore that table. InnoDB: 3) If the file system or the disk is broken, and you cannot remove InnoDB: the .ibd file, you can set innodb_force_recovery > 0 in my.cnf InnoDB: and force InnoDB to continue crash recovery here. 160822 12:57:35 mysqld_safe mysqld from pid file /var/lib/mysql/localhost.mobile.pid ende

上面标记的log,明确表示是非正常关机(InnoDB: Database was not shutdown normally!)导致表结构损坏了,并且在最后给出了三种修复建议:

权限问题。我的文件无此类问题,略过该方案;跳过当前表恢复。我出错的表比较重要,全额无法通过备份恢复,所以该方案也不合适调整强制恢复级别,强制修复表结构。我后续的处理,使用了选择了该方案。

断电时往往数据结构都还是好的,只是mysql事务未完成,有坏的数据在这里,所以有错误。 理论上只要修复表结构、去除坏的数据,mysql就可以正常恢复了。

处理故障

如上所述,权衡之后,我采用了强制启动+导出数据重建的方式。

调整强制恢复级别

找到配置进入编辑模式:# vim /etc/my.cnf 配置文件中调整级别:

## ignore previous roll innodb_force_recovery=6

因为之前也遇到过类似问题,低级别恢复失败了。所以我这里直接使用级别6:跳过启动检测直接进行库表重建。 如果是其他情况的启动异常,具体问题分析后再确定采用哪个级别。

innodb_force_recovery参数说明:

影响整个InnoDB存储引擎的恢复状况,默认值为0,表示当需要恢复时执行所有的恢复操作。 当不能进行有效的恢复操作时,MySQL有可能无法启动,并记录下错误日志。

innodb_force_recovery可以设置为1-6,大的数字包含前面所有数字的影响。 当设置参数值大于0后,可以对表进行select/create/drop操作,但insert/update/delete这类操作是不允许的。

1 (SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页2 (SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash3 (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):不执行前滚的操作。 启动MySQL

配置改好后,就可以启动了。

启动方式选择常用的即可,但不能重复执行,否则提示进程已存在。

/etc/init.d/mysql startmysqld_safe --user=mysql 在这里插入图片描述 更多启动方式,参考《MySQL服务进程的几种启动方式》

正常启动后,注意此时我们只是跳过了启动检查,表数据仍然是坏的。新的数据读写操作进来,仍然可能会出错,甚至导致脏数据滚雪球般放大。因此需要修复数据

修复数据文件

修复数据采用的是导出后重建。

导出数据

使用mysqldump命令导出:

mysqldump -uroot -p --default-character-set=utf8 acc > ./acc.sql

如果数据顺利导出了,可以直接查看下一节重建。

常见问题 提示密码过期

操作时出现了密码过期的提示:在这里插入图片描述 尝试直接登录数据库后,没问题,但任何操作都会提示重设密码: 在这里插入图片描述 原因暂时不清楚,毕竟只是断电,没有数据库升级或其他动作。我直接按提示重设密码(有明白原因的朋友可以留言指导下) 在这里插入图片描述 能正常读了,接着执行备份: 执行命令:mysqldump -uroot -p --default-character-set=utf8 acc > ./acc.sql 输入密码,备份成功。

损坏的是MySQL系统表,无法dump

参见常见问题 - 损坏的是系统表,无法dump,如何恢复

重建

到了这一步,就可以长出一口气了。 此时数据已备份好,最大的风险已经没有了。 为了保险起见,接下来的操作前,可以把数据文件备份掉。

删除目标数据库

尝试直接执行drop database方式删除,但报错了:

在这里插入图片描述 提示表找不到: 在这里插入图片描述 实际查看数据文件目录,文件是存在的。

考虑到数据已经备份,可以直接物理删除目录和里面的frm与ibd文件(谨慎起见,操作前最好备份一下数据dump文件)。

找到mysql的data目录,找到目标库,删除整个目录(mysql无需停掉)再查看,数据库已经删除(比之前少了一个) 在这里插入图片描述 导入备份数据

重启MySQL进入正常读写模式:

将my.cnf中的innodb_force_recovery配置改为0或直接删掉(无该配置项时MySQL默认为0)

重启mysql:

mysqladmin -uroot -p shutdown; mysqld_safe --user=mysql &;

然后重建数据库

create database [库名]; use [库名]; source [备份文件绝对路径,我的是acc.sql]

成功完成还原。 启动应用服务正常,数据库访问正常。 整个恢复过程基本完成。

常见问题

如未进入读写模式,直接重建了数据库,会出现大量类似报错: 在这里插入图片描述 明确提示是只读模式的问题。

这个是innodb_force_recovery大于等于4时,为避免文件损坏面积扩大,mysql采取的保护措施;

此时要进入读写模式,需要先删掉刚刚新建的库: 但会遇到报错: 在这里插入图片描述 错误码39意味着acc目录下有文件; 查看mysql data目录,确认是刚刚创建失败的表,可以直接删除文件目录

总结

我这个案例只是傻瓜式操作,不一定适合所有故障场景,只是作为一种处理参考。 对于故障处理,还有几点补充:

数据操作需慎之又慎,故障出现时一定要保留现场(禁止操作和新的读写污染),做好备份后再开始操作;操作过程中,发现我们的数据库日志实在太大了,好几个G~ 建议如果平时日志没有清理,顺便清理一下;MySQL启动、应用运行看起来没问题。但后来查看数据库错误日志,发现其他库也存在一些问题。因此以后遇到类似情况,最好多检测几次日志,检查所有库,不要遗漏。 其他常见问题 找不到Mysql部署路径

像我这次操作的机器上,MySQL不是我部署的,所以查找路径也花费了一些时间。 尝试过whereis/netstat/iptables等命令,最后直接在mysql默认配置文件/etc/my.cnf中查找到路径 运维对部署路径治理,可以考虑有一个类似同构或固定的说明文档。

MyISAM引擎如何处理

上面所讲的数据库是InnoDB引擎,MyISAM有直接的表修复命令可用

损坏的是系统表,无法dump,如何恢复

这里使用的是mysql5.6的InnoDB数据库,5.6之前直接删除表重启mysql会自动重建

一般故障后,执行写操作就会报核心表错误,比如: 在这里插入图片描述

常见的有五个系统表会一起出错:innodb_table_stats, innodb_index_stats, slave_master_info, slave_relay_log_info, slave_worker_info 因为表结构坏掉、又是mysql系统表,因此无法dump

【解决方法】 MySQL安装目录的share目录下、或者mysql的安装包的script目录下(我的是/usr/share/mysql/)下,有MySQL系统库的建表脚本。找到mysql_system_tables.sql文件,在其中可以找到上述几个表的建表语句。 然后就可以进行重建了。

系统表重建也可能会遇到无法删除的情况,找到data目录下的mysql库,删除对应的文件即可 在这里插入图片描述导入系统表建表脚本时,提示表不存在 在这里插入图片描述 需要清空cache,执行flush tables。然后再执行建表语句就不会报错了。 执行完毕后,重启MySQL即可。

你的问题解决了吗?

未解决。欢迎留言讨论已解决。建议点赞 or 收藏,有相关新内容会持续更新。 没有 是的 问题解决了 评论提建议 点赞 or 收藏 导航在右侧


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3