一次意外断电导致mysql数据库损坏的数据恢复过程

​ mysql在企业开发中不仅存放着大量用户数据表,还存放着其他服务的元数据,这些数据一但无法访问,不仅影响其他业务的进行,同时用户也无法查询自己的数据信息,众所周知,数据是无价的,弄丢了数据的后果极其严重。

​ 昨天就遇到了一次意外断电mysql索引损坏导致mysqld服务无法正常启动的麻烦,断电后重启hadoop集群,开启hiveservice2和matestore元数据服务时发现无法启动,打开hive.log发现是mysql连接失败:

1
2
3
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
......
Caused by: java.net.ConnectException: 拒绝连接 (Connection refused)

随即检查了一下mysql服务,发现mysql服务被意外关闭了,于是又重新启动mysql服务:

1
systemctl restart mysqld;

但是服务并没有顺利启动成功,而是卡住不动了,尝试了几次都是一样卡住,我有点不淡定了,平时mysql服务断开重新开启一下就可以了,于是进入/etc/my.cnf中找到mysql的错误日志并监控日志输出:

1
tail -f /var/log/mysql.log

在另外一个控制台又启动一次服务,发现了从来没有遇到过得报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2020-11-15T09:08:52.532504Z 0 [ERROR] [MY-012712] [InnoDB] Dir slot does not point to right rec 99
len 16384; hex 64c7c9230000023b0000023affffffff00000000292dd74545bf00000000000000000000024400231a58808c000000001a2d00020089008a0000000000000000000000000000000004700000000000000000000000000000000000000000010002001a696e66696d756d0007000b000073757072656d756d000010003000000018338b000000100f1d81000000c601100000000000006f78dfafd5300000000000000000908580e7000018003000000018338c000000100f1d81000000c6011f0000000000005ad8dfafd530a0f0ba889e75d23f90cc9ff8000020003000000018338f000000100f1e820000013801100000000000005ad9dfafd53162475ed6e629e83f90dbc387040028
......
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064c7c923292dd745; asc d # ; : )- EE D # X - p infimum supremum 0 3 ox 0 0 3 Z 0 u ? 0 3 8 Z 1bG^ ) ? ( 0 3 oz 2 B l 0 0 3 Z 2 E 8 0 3 Y Z 32 c { ? Q s @ 0 3 ! \D 4 F @ | H 0 3 ! Z 4 PY P 0 3 $ Z 8 v ( ? *U X 0 3 % \I 9 m4e @ ?Pm ` 0 3 % Z 9 C h 0 3 & Z : Sc, p 0 3 ' ~ dC ; $yi ? b x 0 3
.....
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
Thread pointer: 0x7fb3bc3d4280
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...

2020-11-15T09:08:52.623420Z 0 [ERROR] [MY-011937] [InnoDB] [FATAL] Apparent corruption of an index page [page id: space=580, page number=571] to be written to data file. We intentionally crash the server to prevent corrupt data from ending up in data files.

2020-11-15T09:08:54.724470Z 0 [ERROR] [MY-011906] [InnoDB] Database page corruption on disk or a failed file read of page [page id: space=580, page number=571]. You may have to recover from a backup.

翻译过来意思是:

​ 最可能的情况是,您遇到了一个bug,但这个错误也可能是由硬件故障引起的。

​ mysqld去世的地方。如果在此之后您没有看到任何消息,那么一定有问题,非常错误的……

​ 在磁盘上的数据库页损坏或失败的文件读取页[页id:空间=580,页号=571]。您可能需要从备份中进行恢复。

要写入数据文件的索引页[页id:空格=580,页号=571]明显损坏。我们故意使服务器崩溃,以防止损坏的数据出现在数据文件中。

​ 百度了一阵之后,我意识到是数据库内部有表损坏导致mysql服务无法正常打开了,由于数据库中有上千张表,不可能知道到底是哪里出了问题。这就意味着我要将mysql中所有用户数据表和其他服务的元数据表全部导出到sql文件做备份,然后重新初始化mysql,在把表一个个建回来并重新导入。一想这工作量顿时头皮发麻,但是数据没法访问后果更严重。。。所以硬着头皮来了:

​ 使用强制InnoDB恢复:

​ 编辑/etc/my.cnf文件加入:

1
innodb_force_recovery = 6

innodb_force_recovery影响整个InnoDB存储引擎的恢复状况。默认为0,表示当需要恢复时执行所有的恢复操作(即校验数据页/purge undo/insert buffer merge/rolling back&forward),当不能进行有效的恢复操作时,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操作,会导致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):不执行前滚的操作。

    ​ 然后重启节点,发现mysql服务能启动了,但是无法执行插入更新和删除操作,但终于可以导出宝贵的数据做备份了,我使用了Navicat把mysql中所有数据进行了导出:

    ​ 整个过程用了很久,但数据总算是保存下来了,接下来进入/var/lib/mysql备份整个目录,然后删除目录中所有内容rm -rf ./*将mysql重新初始化。最后进入/etc/my.cnf将innodb重新置为0:

    1
    innodb_force_recovery = 0

    成功启动mysql服务:

    这时候数据库已经重新初始化,需要重新获取初始密码:

    1
    grep 'temporary password' /var/log/mysqld.log

​ 然后进行设置mysql用户的操作,导入之前的数据,重新启动hadoop集群,成功启动hiveservice2和matestore服务。并进入datagrip查了一下,数据完美恢复!还好是测试环境,谢天谢地。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020-2021 ycfn97
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信