记录一次毁灭性的数据丢失找回过程,在写某项目的时候,在考虑对某表上的字段进行逻辑删除,但实际去写的时候写了物理删除,并在使用草稿箱功能的时候,未使用状态码判断,对于旧的数据进行清理,未使用状态码判断,导致正确的数据被持续性的丢失,持续时间长达半个月,导致Mysql的Ibd文件被覆盖,最终寻找到的方法,比如最可笑的时候在新的地方重新挂载ibd文件,被某些博文误导,去尝试发现没有效果,最后在一些大神的文章里面学会了使用Percona Data Recovery Tool 进行Ibd数据找回。
在我的实际学习过程中,对于Mysql的了解比较少,在这次发生的事故中,总结了一些经验,我理解的Mysql的Delete删除方式,他在删除后并不会实际从他的ibd文件中将数据删除,而是做一个标记,文件大小不会被改变,而等待新的数据,来填补这个位置,也就是新的数据覆盖了被删除的数据位置,淡然这是我了解到针对InnoDB来看的。
如果现在已经发生了该情况,首先可以去Mysql中查看是否开启Binlog,在Mysql5.7版本,该功能默认开启,利用以下命令
show variables like 'log_bin';
查看是否查询binlog,可以通过Mysql的方法进行binlog日记查询,找到你之前的插入操作, 重新将数据插入就好了,由于此次问题,我没有开启Binlog,所以这里我先跳过不讲
首先还是在我了解到的一些知识做一下分享
1、这个工具只能对InnoDB/XtraDB表有效,而无法恢复MyISAM表
2、这个工具是以保存的MySQL数据文件进行恢复的,而不用MySQL Server运行。
3、不能保证数据总一定可被恢复。例如,被重写的数据不能被恢复,这种情况下可能需要针对系统或物理的方式来恢复.
4、恢复的最好时机是当你发现数据丢失时,尽快备份MySQL数据文件。
5、使用这个工具需要手动做一些工作,并不是全自动完成的。
6、恢复过程依赖于你对丢失数据的了解程度,在恢复过程中可能需要在不同版本的数据之间做出选择。那么如果你越了解自己的数据,恢复的可能性就越大。
首先,需要理解的是innodb-tools工具不是通过连接到在线的database进行数据恢复,而是通过离线拷贝数据的方式进行的。注意:不要在MySQL运行的时候,直接拷贝InnoDB文件,这样是不安全的,会影响数据恢复过程。
yum install glibc-static -y
运行此命令来安装工具所需要的以来,这里我也不太清楚这个是做什么的,就不多加概述。
wget https://launchpad.net/percona-data-recovery-tool-for-innodb/trunk/release-0.5/+download/percona-data-recovery-tool-for-innodb-0.5.tar.gz
tar -xvf percona-data-recovery-tool-for-innodb-0.5.tar.gz -C /usr/local/
通过以下命令对于Percona Data Recovery Tool 工具进行安装,及解压
cd /usr/local
ln -s percona-data-recovery-tool-for-innodb-0.5 percona-data-recovery-tool
进入解压后根目录下的mysql-source
目录,运行配置命令(注:不运行make命令):
[root@localhost mysql-source]# cd /usr/local/percona-data-recovery-tool/mysql-source/
[root@localhost mysql-source]# ./configure
完成配置步骤后,回到解压后的根目录,运行make命令,编译生成page_parser
和constraints_parser工具
:
[root@localhost mysql-source]# cd ..
[root@localhost percona-data-recovery-tool]# make
page_parser
工具将根据InnoDB的底层实现原理,解析表的页和行结构。constraints_parser工具
暂时不使用,后续还需要在定义表结构之后,重新编译生成它。
InnoDB页的默认大小是16K,每个页属于一个特定表中的一个特定的index。page_parser工具通过读取数据文件,根据页头中的index ID,拷贝每个页到一个单独的文件中。
如果启用了innodb_file_per_table=1
,也就是独立表空间文件,那么将无法完全恢复数据,本人也已经测试过,官方文档也没有提到启用独立表空间是否可以成功,在官方文档中,是设置innodb_file_per_table=0。
运行page_parser工具进行切分:
如果MySQL是5.0之前的版本,InnoDB采取的是REDUNDANT格式,运行以下命令:
./page_parser -4 -f /path/to/ibdata1
如果MySQL是5.0以后的版本,InnoDB采取的是COMPACT格式,运行以下命令:
./page_parser -5 -f /path/to/ibdata1
运行后,page_parser
工具会创建一个pages-的目录,其中TIMESTAMP是UNIX系统时间戳。在这个目录下,为每个index ID,以页的index ID创建一个子目录。例如:
[root@localhost percona-data-recovery-tool]# ./page_parser -5 -f /data/mysql/ibdata1
Opening file: /data/mysql/ibdata1:
2053 ID of device containing file
130915 inode number
33200 protection
1 number of hard links
500 user ID of owner
501 group ID of owner
0 device ID (if special file)
371195904 total size, in bytes
4096 blocksize for filesystem I/O
725000 number of blocks allocated
1394179630 time of last access
1394179669 time of last modification
1394179669 time of last status change
371195904 Size to process in bytes
104857600 Disk cache size in bytes
1.00% done. 2014-03-07 16:31:45 ETA(in 00:04 hours). Processing speed: 1237320 B/sec
2.00% done. 2014-03-07 16:28:27 ETA(in 00:01 hours). Processing speed: 3726376 B/sec
8.80% done. 2014-03-07 16:27:04 ETA(in 00:00 hours). Processing speed: 25231360 B/sec
9.80% done. 2014-03-07 16:28:22 ETA(in 00:01 hours). Processing speed: 3719168 B/sec
20.80% done. 2014-03-07 16:27:00 ETA(in 00:00 hours). Processing speed: 40819863 B/sec
28.25% done. 2014-03-07 16:27:35 ETA(in 00:00 hours). Processing speed: 6912218 B/sec
40.96% done. 2014-03-07 16:27:02 ETA(in 00:00 hours). Processing speed: 47167140 B/sec
51.43% done. 2014-03-07 16:27:03 ETA(in 00:00 hours). Processing speed: 38881628 B/sec
56.49% done. 2014-03-07 16:27:37 ETA(in 00:00 hours). Processing speed: 4698112 B/sec
76.23% done. 2014-03-07 16:27:05 ETA(in 00:00 hours). Processing speed: 73252864 B/sec
83.23% done. 2014-03-07 16:27:07 ETA(in 00:00 hours). Processing speed: 26001408 B/sec
84.74% done. 2014-03-07 16:28:00 ETA(in 00:00 hours). Processing speed: 1117388 B/sec
90.79% done. 2014-03-07 16:27:12 ETA(in 00:00 hours). Processing speed: 22452811 B/sec
99.00% done. 2014-03-07 16:27:12 ETA(in 00:00 hours). Processing speed: 30479427 B/sec
[root@localhost percona-data-recovery-tool]#
[root@localhost percona-data-recovery-tool]# ll pages-1394180806/FIL_PAGE_INDEX/0-1
total 16
-rw-r--r-- 1 root root 16384 Mar 7 16:26 1-00000008.page
我们已经找到了需要的数据,接下来需要找到表结构,创建表定义,将其编译到constraints_parser中,然后使用这个工具从InnoDB页中提取表中的行。
表定义包含了表中的列、列顺序、数据类型。如果MySQL server仍处于运行且表未被drop掉,那么简单实用SHOW CREATE TABLE就可以收集到这些信息。接下来将使用这些表结构信息来创建一个C结构体标识的表定义,然后编译到constraints_parser工具。C结构体的定义存放在include/table_defs.h
中。
最简单的方式是create_defs.pl Perl 脚本,连接到MySQL server,读取SHOW CREATE TABLE的结果,输出生成的表定义到标准输出。下面是个例子,其中直接将结果重定向到了include/table_defs.h中:
[root@localhost percona-data-recovery-tool]# ./create_defs.pl --host=127.0.0.1 --user=root --password=123456 --db=blog --table=name > include/table_defs.h
前面已经提到,我们需要恢复的index ID 0 374,包含数据的页位于pages-1394180806/FIL_PAGE_INDEX/0-374/ 目录。
root@localhost percona-data-recovery-tool]# cd pages-1394180806/FIL_PAGE_INDEX/0-374/
[root@localhost 0-374]# ll
total 36176
-rw-r--r-- 1 root root 16384 Mar 7 16:26 104-00000306.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 106-00000309.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 107-00000310.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 109-00000312.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 110-00000314.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 11-00001416.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 112-00000316.page
-rw-r--r-- 1 root root 16384 Mar 7 16:27 11732-00016419.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 13-00016419.page
-rw-r--r-- 1 root root 16384 Mar 7 16:26 16-00003437.page
输入以下页面进行合并页(也就是恢复全部,其中可能包括已经存在的数据)
[root@localhost percona-data-recovery-tool]# find pages-1394180806/FIL_PAGE_INDEX/0-374/ -type f -name '*.page' | sort -n | xargs cat > pages-1394180806/FIL_PAGE_INDEX/0-374/customer_pages_concatenated
[root@localhost percona-data-recovery-tool]#
生成的结果文件:pages-1394180806/FIL_PAGE_INDEX/0-374/customer_pages_concatenated,将作为constraints_parser
工具的输入。
下面到恢复数据最核心的步骤——运行constraints_parser工具以提取行记录。和``page_parser
工具一样,需要通过-5或-4参数指定InnoDB页格式(COMPACT/REDUNDANT),-f指定输入文件。
回到例子中,我们可以这样运行constraints_parser工具
我们可以这样运行constraints_parser工具
(下面的命令是恢复一个单一的页,也可以直接恢复经过6.1步骤合并所有页之后的文件):
./constraints_parser -5 -f pages-1394180806/FIL_PAGE_INDEX/0-374/76-00003397.page
会输出恢复数据相关语句:
LOAD DATA INFILE '/usr/local/percona-data-recovery-tool/dumps/default/name' REPLACE INTO TABLE `name` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'name\t' (id, word);
既然这样,那么我们就创建dumps/default/文件夹
[root@localhost percona-data-recovery-tool]# pwd
/usr/local/percona-data-recovery-tool
[root@localhost percona-data-recovery-tool]# mkdir dumps/default -p
[root@localhost percona-data-recovery-tool]#
恢复全部页的数据到/dumps/default/million_words
[root@localhost percona-data-recovery-tool]# ./constraints_parser -5 -f pages-1394180806/FIL_PAGE_INDEX/0-374/customer_pages_concatenated >> dumps/default/name
5.98% done
96.42% done
96.86% done
97.30% done
97.74% done
98.19% done
98.63% done
99.07% done
99.51% done
99.96% done
LOAD DATA INFILE '/usr/local/percona-data-recovery-tool/dumps/default/name` REPLACE INTO TABLE `name` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'book\t' (id, word);
我最后使用的办法是到处文件,然后使用vscode打开,将数据导入到Excel,最后使用Navicat来将数据进行导入,通过以上方法最后找回了部分数据,还是建议开启Mysql的Binlog和日记不能,出现错误还可以弥补!