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

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: TwinDB是一款专门用于InnoDB数据恢复的工具,它还有一个名字叫undrop for InnoDB。

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进行数据恢复,感兴趣的朋友可以尝试一下。


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
存储 缓存 算法
innodb文件分析工具innodb_ruby
innodb文件分析工具innodb_ruby的基本使用介绍,帮助更了解Innodb存储引擎的内部结构
249 0
innodb文件分析工具innodb_ruby
|
关系型数据库 MySQL C++
MySQL InnoDB inno_space 工具介绍
**什么是inno_space?** [inno_space ](./https://github.com/baotiao/inno_space) 是一个可以直接访问InnoDB 内部文件的命令行工具, 可以打印出文件的内部结构. Jeremy Cole 用ruby 写了一个类似的工具, 不过不支持MySQL 8.0, 并且ruby 编译以及改动起来特别麻烦, 所以用cpp 重写了一个.
339 0
MySQL InnoDB inno_space 工具介绍