MySQL中使用undrop来恢复drop的表(上)

作者: admin 分类: 公众号存档            2 次浏览 发布时间: 2017-11-20 23:59

公众号:杨建荣的学习笔记 · 作者:r14笔记第47天 · 发布:2017-11-20 23:59:15 · 原文链接

MySQL中可以使用编程语言(比如Python)来解析binlog中DML的逆操作来达到闪回的效果,如果数据不多,手工解析也可以。这也是现在大家碰到的很多DML Flashback的一个基本原理。而如果是DDL,比如DROP,那就得叹声气了。

GitHub上有一个很不错的项目是undrop,基于InnoDB,也就意味着如果你所在的环境有了drop操作还是存在恢复的可能了,当然这个过程需要谨慎,建议大家在测试环境先练习测试论证后再做决定,当然我们希望这个工具永远不要排上用场。

这个项目貌似现在关注的人还不太多,最近看阿里的内核月报中也做了解读。http://mysql.taobao.org/monthly/2017/11/01/,所以引起了我的注意,带着好奇心,自己也测试一把。

安装部署很简单。

git clone https://github.com/twindb/undrop-for-innodb.git
make

这里需要注意的是,你的环境很可能没有flex包,可以在make之前安装一下。

yum install flex

然后我们来尝试编译一个文件sys_parser.c,先配置basedir

basedir=/usr/local/mysql_5.7

gcc `$basedir/bin/mysql_config --cflags` `$basedir/bin/mysql_config --libs` -o sys_parser sys_parser.c

这个工具的一个基本原理就是解析ibdata,从里面解析出我们需要的页的信息,即对应的数据字典。

mysql> show tables like '%SYS%';
+--------------------------------------+
| Tables_in_information_schema (%SYS%) |
+--------------------------------------+
| INNODB_SYS_DATAFILES                 |
| INNODB_SYS_VIRTUAL                   |
| INNODB_SYS_INDEXES                   |
| INNODB_SYS_TABLES                    |
| INNODB_SYS_FIELDS                    |
| INNODB_SYS_TABLESPACES               |
| INNODB_SYS_FOREIGN_COLS              |
| INNODB_SYS_COLUMNS                   |
| INNODB_SYS_FOREIGN                   |
| INNODB_SYS_TABLESTATS                |
+--------------------------------------+
10 rows in set (0.00 sec)

其中这4个数据字典是需要重点关注的。

SYS_COLUMNS | SYS_FIELDS | SYS_INDEXES | SYS_TABLES 

这个工具功能蛮丰富,在目录下有个sakila的文件夹,是一些示例的脚本,我们可以创建一些看起来和业务相关的表,不过实际上我们可以做个减法,只创建一个我们需要重点关注的表,然后导入数据即可。

-rw-r--r--. 1 jeanron jeanron 3231472 Dec 16  2011 sakila-data.sql
-rw-r--r--. 1 jeanron jeanron   50019 Dec 16  2011 sakila.mwb
-rw-r--r--. 1 jeanron jeanron   23099 Dec 16  2011 sakila-schema.sql

否则,这一套表结构还算是比较复杂的,存在外键关联,处理起来需要花些额外的时间。

整个初始化的工作,我们以表actor为例,手工摘取出actor的建表语句,然后运行sakila-data.sql脚本即可。

mysql> checksum table actor;
+--------------+------------+
| Table        | Checksum   |
+--------------+------------+
| sakila.actor | 1702520518 |
+--------------+------------+
1 row in set (0.00 sec)
查询一下表actor的数据量。
mysql> select count(*)from actor;
+----------+
| count(*) |
+----------+
|      200 |
+----------+
1 row in set (0.00 sec)

要解析ibdata,可以使用stream_parser来做。我们指定ibdata的路径。

# ./stream_parser -f /U01/mysql_5.7_test/n1/ibdata1
Opening file: /U01/mysql_5.7_test/n1/ibdata1
File information:
ID of device containing file:        64512
inode number:                       152382
protection:                         100640 (regular file)
number of hard links:                    1
user ID of owner:                      501
group ID of owner:                     501
device ID (if special file):             0
blocksize for filesystem I/O:         4096
number of blocks allocated:         155648
time of last access:            1509475823 Wed Nov  1 02:50:23 2017
time of last modification:      1509476206 Wed Nov  1 02:56:46 2017
time of last status change:     1509476206 Wed Nov  1 02:56:46 2017
total size, in bytes:             79691776 (76.000 MiB)
Size to process:                  79691776 (76.000 MiB)
All workers finished in 1 sec

整个操作很快,会在当前目录下生成一个pages-ibdata1的文件夹,下面包含两个文件夹。

drwxr-xr-x. 2 root root 4096 Nov  1 02:57 FIL_PAGE_INDEX
drwxr-xr-x. 2 root root 4096 Nov  1 02:57 FIL_PAGE_TYPE_BLOB

比如INDEX目录下,存在大量的页,比如下面的输出。

-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000001.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000002.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000003.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000004.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000005.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 0000000000000011.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 0000000000000012.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 0000000000000013.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 0000000000000014.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000015.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000016.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 0000000000000017.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 0000000000000032.page
-rw-r--r--. 1 root root 32768 Nov  1 02:57 0000000000000033.page
-rw-r--r--. 1 root root 16384 Nov  1 02:57 18446744069414584320.page

要解析里面的内容,我们可以使用另外一个命令c_parser,根据关键字sakila/actor来过滤。

./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql  | grep 'sakila/actor'
其中参数4DF,代表文件格式(4代表文件格式是 REDUNDANT),D(D 表示只恢复被删除的记录),f生成文件

然后依次使用c_parser来解析页得到其他几个数据字典的信息,比如(SYS_INDEXES,SYS_COLUMNS,SYS_FIELDS)

后续的内容,在下一篇中会持续更新。

admin

杨建荣,《Oracle DBA工作笔记》《MySQL DBA工作笔记》作者,dbaplus社群发起人之一,腾讯云TVP,现任竞技世界系统部经理,拥有十多年数据库开发和运维经验,目前专注于开源技术、运维自动化和性能调优

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注