MySQL 数据恢复案例

 

本文会从几个方面讲解这个案例,方案确定、方案实施、原理探讨和案例小结,期间会交代诸多细节,以及使用到的技巧。相信读者读完之后,会对以后的数据恢复有所启发。...



0x01 背景介绍


某项目研发 A 删除压测环境大表,等待时间较长,于是直接将 MySQL 数据目录中对应数据库文件删除。于此同时,误删 ibdata 和 MySQL 配置文件。此时 MySQL 已经崩溃,研发从其他机器拷贝误删的数据文件以及配置文件,重启 MySQL,出现Unknown/unsupported storage engine: InnoDB 错误,于是有了接下来的数据恢复。

本文会从几个方面讲解这个案例,方案确定、方案实施、原理探讨和案例小结,期间会交代诸多细节,以及使用到的技巧。相信读者读完之后,会对以后的数据恢复有所启发。

0x02 方案确定


从背景介绍所知,研发遇到的问题是 MySQL 不支持 InnoDB 存储引擎,MySQL 错误日志详细信息如下:

[ERROR] Plugin 'InnoDB' init function returned error.[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.[ERROR] Unknown/unsupported storage engine: InnoDB[ERROR] Aborting

遇到此类问题,我们通常的做法是将 ib_logfile0 和 ib_logfile1 删除,然后重启 MySQL。

首先交代下,MySQL 实例大版本是 5.5,使用独立表空间。此次案例,ibdata 已经不存在,这样会导致数据表不能正常加载。MySQL 5.5 版本,不管使用独立表空间还是共享表空间,ibdata(系统表空间)都会存储 InnoDB 数据表的元数据信息,也就是数据字典,还会存储 undo log、change buffer 和 doublewrite buffer。区别在于,当启用innodb_file_per_table,也就是使用了独立表空间,数据和索引会存储在独立的 ibd 文件中;如果禁用 innodb_file_per_table,也就是使用了共享表空间,数据和索引会存储在 ibdata 中。

那么问题来了,接下来怎么做数据恢复。

可以这样理解,这些存在的 ibd 文件,都是孤立的。也就是说,在没有备份的前提下,怎么从这些孤立的文件中恢复数据。

我们可以按照如下步骤进行恢复:

  1. 获得整个库所有表的表结构;
  2. 新建 MySQL 实例,导入表结构;
  3. 使用 ALTER TABLE dbName.tableName DISCARD TABLESPACE 删除新建的 ibd 文件;
  4. 拷贝对应库对应表的 ibd 文件到对应目录,并更改权限;
  5. 使用 ALTER TABLE dbName.tableName IMPORT TABLESPACE 导入拷贝的 ibd 文件。
导入拷贝的 ibd 文件,会遇到如下错误:

ERROR 1030 (HY000): Got error -1 from storage engine

对应 MySQL 错误日志如下:

160419 16:06:08  InnoDB: Error: tablespace id and flags in file './dbName/tableName.ibd' are 243 and 0, but in the InnoDB
InnoDB: data dictionary they are 247 and 0.
InnoDB: Have you moved InnoDB .ibd files around without using the
InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?
InnoDB: Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/innodb-troubleshooting-datadict.html
InnoDB: for how to resolve the issue.
160419 16:06:08  InnoDB: cannot find or open in the database directory the .ibd file of
InnoDB: table `dbName`.`tableName`InnoDB: in ALTER TABLE ... IMPORT TABLESPACE

从日志中我们可以知道,dbName.tableName 旧的表空间 id 为 243,而数据字典中新的表空间 id 为 247。也就是说,旧的 ibd 文件和新的 ibd 文件,表空间 id 不一致,导致 InnoDB 存储引擎不能正常加载数据表。

接下来,恢复步骤调整如下:

  1. 获得整个库所有表的表结构;
  2. 新建 MySQL 实例,导入表结构;
  3. 使用 ALTER TABLE dbName.tableName DISCARD TABLESPACE 删除新建的 ibd 文件;
  4. 拷贝对应库对应表的 ibd 文件到对应目录,并更改权限;
  5. 使用 ALTER TABLE dbName.tableName IMPORT TABLESPACE 导入拷贝的 ibd 文件;
  6. 分析 MySQL 错误日志,获取所有表的新旧表空间 id;
  7. 结合 xxd 和 sed 替换 ibd 文件中的表空间 id;
  8. 使用 ALTER TABLE dbName.tableName IMPORT TABLESPACE 再次导入替换过表空间 id 的 ibd 文件;
  9. 修改配置文件,将 innodb_force_recovery 设置为 6,并重启 MySQL;
  10. 使用 mysqldump 备份数据;
  11. 再次新建实例,导入逻辑备份文件。

0x03 方案实施


方案确定好之后,接下来讲解实施过程,以及期间使用的一些技巧。

3.1 获取表结构并导入

注:此小节对应恢复步骤的 1 和 2。

压测环境没有备份,但是另一套测试环境的表结构与压测环境一致,只是数据有所差异,所以,获取表结构比较容易。

导入表结构没有什么好说明的地方,注意导入 SQL 的权限和字符集。

3.2 重建表空间

注:此小节对应恢复步骤的 3~5。

由于是整库恢复,数据库和表较多,所以使用脚本处理,具体可以参考脚本:「MySQL 高可用架构在业务层面的分析研究

PHP与MySQL通讯那点事

常见HTTP状态


    关注 优才网


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册