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 文件,都是孤立的。也就是说,在没有备份的前提下,怎么从这些孤立的文件中恢复数据。
我们可以按照如下步骤进行恢复:
- 获得整个库所有表的表结构;
- 新建 MySQL 实例,导入表结构;
- 使用 ALTER TABLE dbName.tableName DISCARD TABLESPACE 删除新建的 ibd 文件;
- 拷贝对应库对应表的 ibd 文件到对应目录,并更改权限;
- 使用 ALTER TABLE dbName.tableName IMPORT TABLESPACE 导入拷贝的 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 存储引擎不能正常加载数据表。
接下来,恢复步骤调整如下:
- 获得整个库所有表的表结构;
- 新建 MySQL 实例,导入表结构;
- 使用 ALTER TABLE dbName.tableName DISCARD TABLESPACE 删除新建的 ibd 文件;
- 拷贝对应库对应表的 ibd 文件到对应目录,并更改权限;
- 使用 ALTER TABLE dbName.tableName IMPORT TABLESPACE 导入拷贝的 ibd 文件;
- 分析 MySQL 错误日志,获取所有表的新旧表空间 id;
- 结合 xxd 和 sed 替换 ibd 文件中的表空间 id;
- 使用 ALTER TABLE dbName.tableName IMPORT TABLESPACE 再次导入替换过表空间 id 的 ibd 文件;
- 修改配置文件,将 innodb_force_recovery 设置为 6,并重启 MySQL;
- 使用 mysqldump 备份数据;
- 再次新建实例,导入逻辑备份文件。
0x03 方案实施
方案确定好之后,接下来讲解实施过程,以及期间使用的一些技巧。
3.1 获取表结构并导入
压测环境没有备份,但是另一套测试环境的表结构与压测环境一致,只是数据有所差异,所以,获取表结构比较容易。注:此小节对应恢复步骤的 1 和 2。
导入表结构没有什么好说明的地方,注意导入 SQL 的权限和字符集。
3.2 重建表空间
由于是整库恢复,数据库和表较多,所以使用脚本处理,具体可以参考脚本:「MySQL 高可用架构在业务层面的分析研究注:此小节对应恢复步骤的 3~5。
PHP与MySQL通讯那点事
常见HTTP状态
关注 优才网
微信扫一扫关注公众号