摘要:
在实际工作中遇到了mysql服务器硬盘挂掉的情况,并且无slave无备份。此时就只能去恢复硬盘的数据了。本文根据一次实战操作整理,分别用4种办法尝试修复数据。我们首先拿到了坏硬盘上的文件,在新服务器上安装同样版本的mysql准备恢复。
普通恢复:
此方式是把mysql的数据目录与my.cnf文件拷贝到新数据库目录,正常启动数据库。如果数据目录没有损坏,正常启动后应能正常读写数据,error日志无报错。
但是我们恢复时报了大量的错误,由此可见ibdata文件或redo日志已经被损坏,继续使用其他方式恢复。
附部分error信息:
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 5.
InnoDB: You may have to recover from a backup.
InnoDB: See also http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Error: space id in fsp header 3221244024, but in the page header 268454008
InnoDB: Error: tablespace id 4294967295 in file .\game\area_element_table.ibd is not sensible
InnoDB: Cannot continue operation.
InnoDB: You can try to recover the database with the my.cnf
InnoDB: option:
InnoDB: innodb_force_recovery=6
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
innodb_force_recovery方式:
我们根据上面的error日志提供的信息,在my.cnf的[mysqld]里面加入参数innodb_force_recovery,使用1-6级逐步尝试恢复。参考链接:http://who0168.blog.51cto.com/253401/551068
这种方式对于常规的数据库崩溃或服务器崩溃是奏效的,可以绕过损坏的redo log。但我们实际操作时将级别提升至6仍无法启动,说明ibdata可能有损坏。继续下面的修复方式。
附部分error信息:
error日志和上面的差不多,这里仅贴出有差异的部分
InnoDB: The user has set SRV_FORCE_NO_LOG_REDO on
InnoDB: Skipping log redo
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 7.
InnoDB: Error: trying to access page number 16766859 in space 0,
InnoDB: space name .\ibdata1,
InnoDB: which is outside the tablespace bounds.
InnoDB: Byte offset 0, len 16384, i/o type 10.
InnoDB: If you get this error at mysqld startup, please check that
InnoDB: your my.cnf matches the ibdata files that you have in the
InnoDB: MySQL server.
修复ibdata方式:
独立表空间模式下,ibdata的作用是存放内部数据字典和重作日志。 在ibdata文件丢失或损坏的情况下,利用frm和ibd文件,以及数据库的表结构,也可以尝试恢复数据。
1、DISCARD、IMPORT TABLESPACE方式:
注:此方式未修复成功,仅供参考
1)新建数据库,创建需要恢复的数据库的表结构。
2)service mysqld stop,将需要恢复的frm文件覆盖刚刚新建的frm,并设置权限为mysql。service mysqld start,启动时加上参数innodb_force_recovery=6。
3)ALTER TABLE xx DISCARD TABLESPACE; 复制ibd文件到数据目录。service mysqld stop
4)service mysqld start,启动时加上参数innodb_force_recovery=6。再ALTER TABLE xx IMPORT TABLESPACE;
2、修改ibd文件方式:
注:此方式亲测可用
1)新建数据库,创建需要恢复的数据库的表结构。
2)使用vim打开此表的ibd文件,16进制查看
[root@localhost test]# vim -b tmp.ibd
:%!xxd
3)使用vim打开要恢复的ibd文件,16进制查看
4)修改要恢复的ibd文件,将红方框中的值修改的和刚刚创建的新表的ibd文件一致。看到后面大段的0000没,我们只需要修改文件头就可以了。00000c0以后的不用修改。
[root@localhost test]# vim -b tmp.ibd:%!xxd -r #一定要先执行这一步
:wq
5)拿需要恢复的ibd文件覆盖刚刚创建的新表的ibd文件。修改文件权限为mysql用户。
6)重启mysql,重启时加上参数innodb_force_recovery = 6。
7)执行select操作,读取正常,但无法执行更新操作。将数据dump出来,重建表。找回数据成功。
mysqlbinlog方式:
在沟通的过程中我们了解到,在此前他们对数据库进行过一次清空操作。如果能找到当时清空数据库的时间点,利用mysqlbinlog进行一次日志回放,也是可行的。
实际操作过程中对方无法提供清空数据库的准确时间点,回放binlog时错误不断,数据的准确性无法保证,最终作罢。
此方式的适用场景:
1)有此前的数据库备份及备份后的binlog
2)能查到清空数据库的时间点
参考资料:
1.http://dev.mysql.com/doc/refman/5.5/en/forcing-innodb-recovery.html
2.http://who0168.blog.51cto.com/253401/551068
3.Mysql ibdata 丢失或损坏如何通过frm&ibd 恢复数据 http://www.lanceyan.com/tech/mysql/lost-ibdata-recover-data.html
4.MySQL:如何从ibd文件中恢复数据 http://www.dedecms.com/knowledge/data-base/mysql/2012/0819/7558.html