InnoDB数据恢复的工具——TwinDB介绍

TwinDB是一款专门用于InnoDB数据恢复的工具,它还有一个名字叫undrop for InnoDB。

安装方法

使用下面的命令进行下载:

$ wget https://github.com/chhabhaiya/undrop-for-innodb/archive/master.zip

或者:

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

在编译前需要安装下面的依赖包:

# apt install make gcc flex bison

使用make生成执行文件:

# make

使用方法

1.恢复表结构

当MySQL无法启动时,TwinDB工具集可以从系统表空间文件ibdata1中直接恢复表结构。
这个工具集安装完成后dictionary目录下面有创建4个数据字典表的SQL语句:

# ls dictionary/

SYS_COLUMNS.sql  SYS_FIELDS.sql  SYS_INDEXES.sql  SYS_TABLES.sql

创建一个data_recovered数据库:

# mysqladmin create data_recovered

在这个数据库中生成4个数据字典表:

# cat dictionary/SYS_* | mysql data_recovered

检查一下生成的数据:

# mysqlshow -vv data_recovered

Database: data_recovered

+-------------+----------+------------+

|   Tables    | Columns  | Total Rows |

+-------------+----------+------------+

| SYS_COLUMNS |        7 |          0 |

| SYS_FIELDS  |        3 |          0 |

| SYS_INDEXES |        7 |          0 |

| SYS_TABLES  |        8 |          0 |

+-------------+----------+------------+

4 rows in set.

使用工具集中的stream_parser对系统表空间文件ibdata1进行解析:

# ./stream_parser -f /var/lib/mysql/ibdata1

Opening file: /var/lib/mysql/ibdata1

File information:

 

ID of device containing file:        64768

inode number:                     29252470

protection:                         100640 (regular file)

number of hard links:                    1

user ID of owner:                       27

group ID of owner:                      27

device ID (if special file):             0

blocksize for filesystem I/O:         4096

number of blocks allocated:          24576

Opening file: /var/lib/mysql/ibdata1


解析完成后将解析的数据放在当前目录下的pages-ibdata1目录下:

# ls pages-ibdata1/*

pages-ibdata1/FIL_PAGE_INDEX:

0000000000000001.page  0000000000000011.page  0000000000000016.page  0000000000000026.page  0000000000000043.page

0000000000000002.page  0000000000000012.page  0000000000000017.page  0000000000000032.page  0000000000000044.page

0000000000000003.page  0000000000000013.page  0000000000000020.page  0000000000000033.page  0000000000000045.page

0000000000000004.page  0000000000000014.page  0000000000000024.page  0000000000000041.page  18446744069414584320.page

0000000000000005.page  0000000000000015.page  0000000000000025.page  0000000000000042.page

 

pages-ibdata1/FIL_PAGE_TYPE_BLOB:

根据MySQL的源码,这4个数据字典表的数据分别位于前面4个页中,使用下面的4条语句从这4个页中读出数据:

# ./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t \

 dictionary/SYS_TABLES.sql > dumps/default/SYS_TABLES \

 2>dumps/default/SYS_TABLES.sql

 

# ./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000002.page -t \

 dictionary/SYS_COLUMNS.sql > dumps/default/SYS_COLUMNS \

 2>dumps/default/SYS_COLUMNS.sql

 

# ./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t \

 dictionary/SYS_INDEXES.sql > dumps/default/SYS_INDEXES \

 2>dumps/default/SYS_INDEXES.sql


# ./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000004.page -t \

 dictionary/SYS_FIELDS.sql > dumps/default/SYS_FIELDS \

 2>dumps/default/SYS_FIELDS.sql

使用下面的命令将数据导入到这4个表中:

# cat dumps/default/*.sql |  mysql data_recovered

导出完成后再检查一下:

#  mysqlshow -vv data_recovered
Database: data_recovered
+-------------+----------+------------+
|   Tables    | Columns  | Total Rows |
+-------------+----------+------------+
| SYS_COLUMNS |        7 |        157 |
| SYS_FIELDS  |        3 |         50 |
| SYS_INDEXES |        7 |         35 |
| SYS_TABLES  |        8 |         28 |
+-------------+----------+------------+

4 rows in set.

这样所有表的数据字典信息都恢复到这4个表中了,下面编译生成sys_parser工具:

# make sys_parser

/bin/mysql_config

cc -o sys_parser sys_parser.c `mysql_config --cflags` `mysql_config --libs`

使用sys_parser工具可以从数据字典表中生成任意表的建表语句,它的用法如下:

# ./sys_parser 

sys_parser [-h <host>] [-u <user>] [-p <passowrd>] [-d <db>] databases/table

例如下面的语句生成world.city表的建表语句:

# ./sys_parser -u root -p dingjia  -d data_recovered world/city

CREATE TABLE `city`(

     `ID` INT NOT NULL,

     `Name` CHAR(35) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci' NOT NULL,

     `CountryCode` CHAR(3) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci' NOT NULL,

     `District` CHAR(20) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci' NOT NULL,

     `Population` INT NOT NULL,

     PRIMARY KEY (`ID`)

) ENGINE=InnoDB;

2.恢复删除的表
TwinDB工具集可以用于恢复刚刚被误删除的表,如果误删除了world.city表,这个表对应的独立表空间文件/var/lib/mysql/world/city.ibd也被删除,使用前面的命令可以恢复这个表的表结构,然后使用下面的命令恢复InnoDB的页:

# ./stream_parser -f /dev/sda2 -t 59.5G

这里的/dev/sda2是world.city表所在的硬盘分区,59.5G是这个分区的大小,如果这个表是放在通用表空间,删除这个表时不会同时删除这个表空间,应将上面命令中的/dev/sda2换成对应的表空间文件名。stream_parser会扫描这个分区,将所有的InnoDB页都解析出来放在下面的目录:

# ls pages-sda2/FIL_PAGE_INDEX

0000000000000001.page  0000000000000033.page  0000000000000062.page  0000000000000092.page  0000000000000125.page

0000000000000002.page  0000000000000034.page  0000000000000063.page  0000000000000093.page  0000000000000126.page

0000000000000003.page  0000000000000035.page  0000000000000064.page  0000000000000094.page  0000000000000127.page

...

根据之前生成的数据字典信息,使用下面的命令查询出world.city的表ID:

mysql> select * from data_rrecovered.SYS_TABLES where name='world/city';

+------------+----+--------+------+--------+---------+--------------+-------+

| NAME       | ID | N_COLS | TYPE | MIX_ID | MIX_LEN | CLUSTER_NAME | SPACE |

+------------+----+--------+------+--------+---------+--------------+-------+

| world/city | 40 |      5 |   33 |      0 |      80 |              |    23 |

+------------+----+--------+------+--------+---------+--------------+-------+

1 row in set (0.00 sec)

知道world.city的表ID为40后,再查询主键的ID:

mysql> select * from data_recovered.SYS_INDEXES where table_id=40;

+----------+----+-------------+----------+------+-------+---------+

| TABLE_ID | ID | NAME        | N_FIELDS | TYPE | SPACE | PAGE_NO |

+----------+----+-------------+----------+------+-------+---------+

|       40 | 41 | PRIMARY     |        1 |    3 |    23 |       3 |

|       40 | 42 | CountryCode |        1 |    0 |    23 |       4 |

+----------+----+-------------+----------+------+-------+---------+

2 rows in set (0.00 sec)

知道主键的ID为41,因为InnoDB都是索引组织表,数据按主键进行存放,因此这个表的数据就在第41页,可以使用c_parser解析第41页,将数据输出到文件中:

# ./c_parser -6f pages-city.ibd/FIL_PAGE_INDEX/0000000000000041.page -t city.sql \

> > dumps/default/city \

> 2>dumps/default/city.sql

查看生成的SQL文件:

# cat dumps/default/city.sql

SET FOREIGN_KEY_CHECKS=0;

LOAD DATA LOCAL INFILE '/root/install/undrop-for-innodb-master/dumps/default/city' REPLACE INTO TABLE `city` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'city\t' (`ID`, `Name`, `CountryCode`, `District`, `Population`);

执行这个SQL文件将数据加载到数据库中:

# cat dumps/default/city.sql | mysql world

数据恢复成功!

3.从损坏的表空间中挽救数据
造成表空间损坏的原因很多:硬盘坏道、多个进程同时访问数据文件、突然掉电等。遇到表空间损坏时,TwinDB工具集可以跳过损坏的部分,尽量读取多的数据。
表空间损坏后可能造成MySQL实例无法启动,或者客户端在查询损坏的表时crash,在MySQL的错误日志里可能会有下面的提示:

0 [ERROR] InnoDB: Database page corruption on disk or a failed file
read of page [page id: space=24, page number=4]. You may have to
recover from a backup.
使用innochecksum检查损坏的表可能会有下面的提示:

# innochecksum  /var/lib/mysql/world/country.ibd

Fail: page 0 invalid

Exceeded the maximum allowed checksum mismatch count::0

这时可以使用TwinDB工具集将对应的表空间分成页:

# ./stream_parser -f /var/lib/mysql/world/country.ibd

这个命令执行后会生成一个页:

# ls pages-country.ibd/FIL_PAGE_INDEX/

0000000000000043.page

使用下面的命令从第43页中导出数据:

# ./c_parser -6f pages-country.ibd/FIL_PAGE_INDEX/0000000000000043.page \

 -t country.sql > dumps/default/country 2> dumps/default/country.sql

对导出的文件dumps/default/city进行检查,确认无误后再导入到重新创建的表中:

# cat dumps/default/city.sql | mysql world

以上内容是关于TwinDB的介绍,可以使用其对InnoDB进行数据恢复,感兴趣的朋友可以尝试一下。

文章下方是我的微信,欢迎加我(托业890分的Oracle ACE)。👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姚远Oracle ACE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值