使用undrop-for-innodb工具在無備份的情況下恢復mysql表
最近一個朋友說,程序誤刪了一張表,但是沒有備份。我一心想,這不是涼涼了。因為按照正常的情況,如果誤刪了表,在有備份的情況下,可以通過備份+binlog的方式找回數據。如果沒有備份的話,想找回數據基本是沒什麽希望了。本著死馬當活馬醫的態度,在網上google了一陣,發現了竟然還有undrop-for-innodb這一個工具。
undrop-for-innodb工具按照描述,是可以實現在無備份的情況下,通過掃描ibdata1文件和磁盤文件,來找回刪除表的數據。話不多說,立馬實驗一下。
恢復步驟
使用undrop-for-innodb工具分兩種情況,分別是innodb_file_per_table=OFF和innodb_file_per_table=ON兩種情況。innodb_file_per_table參數描述了innodb存儲引擎存儲數據的方式。如果為OFF,則庫表的所有數據都存放在ibdata*的共享表空間內,若為ON,則每個表會生成獨立的文件來存儲數據。
在如今的mysql版本中,innodb_file_per_table參數默認為ON,於是這裏來重點講一下innodb_file_per_table=ON的這種情況。
一:安裝undrop-for-innodb工具。
# git clone https://github.com/twindb/undrop-for-innodb.git # yum install -y make gcc flex bison # cd undrop-for-innodb # make
安裝完之後,會在undrop-for-innodb目錄下生成stream_parser和c_parser文件。
二:模擬mysql表誤刪操作:
這裏我有一個iceny.assets_host_auth,裏面存放了一些我自己系統的用戶信息,如下:
刪除assets_host_auth表:
mysql> drop table assets_host_auth; Query OK, 0 rows affected (0.01 sec)
三,掃描磁盤頁以及ibdata文件
# df -k Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/centos-root 19703808 6701800 13002008 35% / devtmpfs 922464 0 922464 0% /dev tmpfs 933524 0 933524 0% /dev/shm tmpfs 933524 16952 916572 2% /run tmpfs 933524 0 933524 0% /sys/fs/cgroup /dev/sda1 201380 123252 78128 62% /boot tmpfs 186708 0 186708 0% /run/user/0 # ./stream_parser -f /dev/mapper/centos-root -t 19703808k Opening file: /dev/mapper/centos-root File information: ID of device containing file: 5 inode number: 2006 protection: 60660 (block device) number of hard links: 1 user ID of owner: 0 group ID of owner: 6 device ID (if special file): 64768 blocksize for filesystem I/O: 4096 number of blocks allocated: 0 time of last access: 1533986548 Sat Aug 11 07:22:28 2018 time of last modification: 1533984737 Sat Aug 11 06:52:17 2018 time of last status change: 1533984737 Sat Aug 11 06:52:17 2018 total size, in bytes: 0 (0.000 exp(+0)) Size to process: 20176699392 (18.791 GiB) Opening file: /dev/mapper/centos-root File information: ID of device containing file: 5 inode number: 2006 protection: 60660 (block device) number of hard links: 1 user ID of owner: 0 group ID of owner: 6 device ID (if special file): 64768 blocksize for filesystem I/O: 4096 number of blocks allocated: 0 time of last access: 1533986548 Sat Aug 11 07:22:28 2018 time of last modification: 1533984737 Sat Aug 11 06:52:17 2018 time of last status change: 1533984737 Sat Aug 11 06:52:17 2018 total size, in bytes: 0 (0.000 exp(+0)) Size to process: 20176699392 (18.791 GiB) Worker(0): 1.16% done. 2018-08-13 20:20:29 ETA(in 00:06:06). Processing speed: 25.949 MiB/sec Worker(1): 1.16% done. 2018-08-13 20:22:01 ETA(in 00:07:37). Processing speed: 20.766 MiB/sec Worker(0): 2.24% done. 2018-08-13 20:20:29 ETA(in 00:06:02). Processing speed: 25.949 MiB/sec Worker(1): 2.24% done. 2018-08-13 20:25:05 ETA(in 00:10:34). Processing speed: 14.828 MiB/sec Worker(0): 3.32% done. 2018-08-13 20:23:30 ETA(in 00:08:57). Processing speed: 17.300 MiB/sec Worker(1): 3.32% done. 2018-08-13 20:20:33 ETA(in 00:05:58). Processing speed: 25.957 MiB/sec Worker(0): 4.40% done. 2018-08-13 20:22:01 ETA(in 00:07:23). Processing speed: 20.760 MiB/sec Worker(1): 4.40% done. 2018-08-13 20:20:33 ETA(in 00:05:54). Processing speed: 25.949 MiB/sec Worker(0): 5.48% done. 2018-08-13 20:20:32 ETA(in 00:05:50). Processing speed: 25.949 MiB/sec Worker(1): 5.48% done. 2018-08-13 20:22:02 ETA(in 00:07:18). Processing speed: 20.759 MiB/sec Worker(0): 6.56% done. 2018-08-13 20:22:00 ETA(in 00:07:13). Processing speed: 20.759 MiB/sec Worker(1): 6.56% done. 2018-08-13 20:20:34 ETA(in 00:05:46). Processing speed: 25.949 MiB/sec Worker(0): 7.64% done. 2018-08-13 20:20:33 ETA(in 00:05:42). Processing speed: 25.949 MiB/sec Worker(1): 7.64% done. 2018-08-13 20:20:34 ETA(in 00:05:42). Processing speed: 25.949 MiB/sec Worker(0): 8.71% done. 2018-08-13 20:19:07 ETA(in 00:04:13). Processing speed: 34.616 MiB/sec Worker(0): 9.80% done. 2018-08-13 20:16:18 ETA(in 00:01:23). Processing speed: 104.000 MiB/sec Worker(1): 8.71% done. 2018-08-13 20:19:08 ETA(in 00:04:13). Processing speed: 34.599 MiB/sec Worker(0): 11.21% done. 2018-08-13 20:15:58 ETA(in 00:01:02). Processing speed: 136.000 MiB/sec Worker(1): 9.79% done. 2018-08-13 20:19:08 ETA(in 00:04:10). Processing speed: 34.599 MiB/sec Worker(0): 12.29% done. 2018-08-13 20:20:25 ETA(in 00:05:25). Processing speed: 25.953 MiB/sec Worker(1): 10.87% done. 2018-08-13 20:19:08 ETA(in 00:04:07). Processing speed: 34.599 MiB/sec Worker(1): 11.95% done. 2018-08-13 20:19:08 ETA(in 00:04:04). Processing speed: 34.605 MiB/sec Worker(0): 13.37% done. 2018-08-13 20:23:07 ETA(in 00:08:01). Processing speed: 17.299 MiB/sec Worker(1): 13.03% done. 2018-08-13 20:19:08 ETA(in 00:04:01). Processing speed: 34.599 MiB/sec
# ./stream_parser -f /opt/data/mysql_3306/ibdata1
掃描完之後,會在當前目錄下生成相關的目錄:
四,找出assets_host_auth表數據所在的磁盤頁。
1,找出assets_host_auth的表ID:
./c_parser -4Df ./pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t ./dictionary/SYS_TABLES.sql | grep assets 000000002D0A 2A0000017E28FC SYS_TABLES "iceny/assets\_host\_auth" 185 4 33 0 80 "" 178 SET FOREIGN_KEY_CHECKS=0; LOAD DATA LOCAL INFILE '/tmp/undrop-for-innodb-master/dumps/default/SYS_TABLES000000002D0A 2A0000017E28FC SYS_TABLES "iceny/assets\_host\_auth" 185 4 33 080 "" 178 ' REPLACE INTO TABLE `SYS_TABLES` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'SYS_TABLES\t' (`NAME`, `ID`, `N_COLS`, `TYPE`, `MIX_ID`, `MIX_LEN`, `CLUSTER_NAME`, `SPACE`); -- STATUS {"records_expected": 122, "records_dumped": 34, "records_lost": true} STATUS END
表ID為表名後面的那個數字,這裏為185。
2,利用找出來的表ID,查找assets_host_auth的磁盤頁ID:
# ./c_parser -4Df ./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t ./dictionary/SYS_INDEXES.sql | grep 185 000000002D0A 2A0000017E27EB SYS_INDEXES 185 335 "PRIMARY" 1 3 178 4294967295 000000001140 2500000139185D SYS_INDEXES 119 207 "PRIMARY" 1 3 105 4294967295 000000002D0A 2A0000017E27EB SYS_INDEXES 185 335 "PRIMARY" 1 3 178 4294967295 000000001140 2500000139185D SYS_INDEXES 119 207 "PRIMARY" 1 3 105 4294967295 SET FOREIGN_KEY_CHECKS=0;
這裏可以明細那看到,ID185對應的數值是335,這裏的335就是assets_host_auth數據所在的的磁盤頁ID。
3,查看掃描的磁盤頁中是否存在335的page:
# ll pages-centos-root/FIL_PAGE_INDEX/0000000000000335.page -rw-r--r-- 1 root root 65536 Aug 13 20:31 pages-centos-root/FIL_PAGE_INDEX/0000000000000335.page
可以看到335page確實存在。
4,創建assets_host_auth.sql文件,內容是assets_host_auth表的數據結構:
# vi iceny/assets_host_auth.sql CREATE TABLE `assets_host_auth` ( `id` int(11) NOT NULL AUTO_INCREMENT, `host_ip` varchar(20) NOT NULL, `password` varchar(100) DEFAULT NULL, `env` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
5,利用存在的磁盤page查看assets_host_auth數據是否還在;
./c_parser -6f pages-centos-root/FIL_PAGE_INDEX/0000000000000335.page -t iceny/assets_host_auth.sql | head -5 -- Page id: 3, Format: COMPACT, Records list: Valid, Expected records: (5 5) 000000002690 DF000001C10110 assets_host_auth 1 "192.168.204.128" "123456" "cmh\_test" 000000002690 DF000001C1011D assets_host_auth 17 "192.168.1.11" "]t;:<8qCLfse+8LZZhK+11" "HB" 000000002690 DF000001C1012A assets_host_auth 19 "192.168.1.12" "]t;:<8qCLfse+8LZZhK+12" "HB" 000000002690 DF000001C10137 assets_host_auth 20 "192.168.1.113" "]t;:<8qCLfse+8LZZhK+113" "HB"
這裏可以看到找到了一些相關的數據。
6,導出數據,生成sql導入文件:
# ./c_parser -6f pages-centos-root/FIL_PAGE_INDEX/0000000000000335.page -t iceny/assets_host_auth.sql > dumps/default/assets_host_auth 2> dumps/default/assets_host_auth.sql # more dumps/default/assets_host_auth.sql SET FOREIGN_KEY_CHECKS=0; LOAD DATA LOCAL INFILE '/tmp/undrop-for-innodb-master/dumps/default/assets_host_auth' REPLACE INTO TABLE `assets_host_auth` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STA RTING BY 'assets_host_auth\t' (`id`, `host_ip`, `password`, `env`); -- STATUS {"records_expected": 20, "records_dumped": 20, "records_lost": false} STATUS END # more /tmp/undrop-for-innodb-master/dumps/default/assets_host_auth -- Page id: 3, Format: COMPACT, Records list: Valid, Expected records: (5 5) 000000002690 DF000001C10110 assets_host_auth 1 "192.168.204.128" "123456" "cmh\_test" 000000002690 DF000001C1011D assets_host_auth 17 "192.168.1.11" "]t;:<8qCLfse+8LZZhK+11" "HB" 000000002690 DF000001C1012A assets_host_auth 19 "192.168.1.12" "]t;:<8qCLfse+8LZZhK+12" "HB" 000000002690 DF000001C10137 assets_host_auth 20 "192.168.1.113" "]t;:<8qCLfse+8LZZhK+113" "HB" 000000002690 DF000001C10144 assets_host_auth 21 "192.168.1.15" "]t;:<8qCLfse+8LZZhK+15" "HB" -- Page id: 3, Found records: 5, Lost records: NO, Leaf page: YES -- Page id: 3, Format: COMPACT, Records list: Valid, Expected records: (5 5) 000000002690 DF000001C10110 assets_host_auth 1 "192.168.204.128" "123456" "cmh\_test" 000000002690 DF000001C1011D assets_host_auth 17 "192.168.1.11" "]t;:<8qCLfse+8LZZhK+11" "HB" 000000002690 DF000001C1012A assets_host_auth 19 "192.168.1.12" "]t;:<8qCLfse+8LZZhK+12" "HB" 000000002690 DF000001C10137 assets_host_auth 20 "192.168.1.113" "]t;:<8qCLfse+8LZZhK+113" "HB" 000000002690 DF000001C10144 assets_host_auth 21 "192.168.1.15" "]t;:<8qCLfse+8LZZhK+15" "HB" -- Page id: 3, Found records: 5, Lost records: NO, Leaf page: YES -- Page id: 3, Format: COMPACT, Records list: Valid, Expected records: (5 5) 000000002690 DF000001C10110 assets_host_auth 1 "192.168.204.128" "123456" "cmh\_test" 000000002690 DF000001C1011D assets_host_auth 17 "192.168.1.11" "]t;:<8qCLfse+8LZZhK+11" "HB" 000000002690 DF000001C1012A assets_host_auth 19 "192.168.1.12" "]t;:<8qCLfse+8LZZhK+12" "HB" 000000002690 DF000001C10137 assets_host_auth 20 "192.168.1.113" "]t;:<8qCLfse+8LZZhK+113" "HB" 000000002690 DF000001C10144 assets_host_auth 21 "192.168.1.15" "]t;:<8qCLfse+8LZZhK+15" "HB" -- Page id: 3, Found records: 5, Lost records: NO, Leaf page: YES -- Page id: 3, Format: COMPACT, Records list: Valid, Expected records: (5 5) 000000002690 DF000001C10110 assets_host_auth 1 "192.168.204.128" "123456" "cmh\_test" 000000002690 DF000001C1011D assets_host_auth 17 "192.168.1.11" "]t;:<8qCLfse+8LZZhK+11" "HB" 000000002690 DF000001C1012A assets_host_auth 19 "192.168.1.12" "]t;:<8qCLfse+8LZZhK+12" "HB" 000000002690 DF000001C10137 assets_host_auth 20 "192.168.1.113" "]t;:<8qCLfse+8LZZhK+113" "HB" 000000002690 DF000001C10144 assets_host_auth 21 "192.168.1.15" "]t;:<8qCLfse+8LZZhK+15" "HB" -- Page id: 3, Found records: 5, Lost records: NO, Leaf page: YES
可以看到,我們已經找回了我們所刪除的數據,最後要做的,就是把這些數據導入數據庫中去:
7,把數據導入數據庫:
#導入表結構 mysql> use iceny; Database changed mysql> source /tmp/undrop-for-innodb-master/iceny/assets_host_auth.sql Query OK, 0 rows affected (0.21 sec)
導入數據,並查看:
對比之前的數據,發現並無差異,至此,我們就通過undrop-for-innodb工具在無備份的情況下找回了數據。
undrop-for-innodb的一些問題(個人猜想)
由於undrop-for-innodb是通過掃描磁盤頁來找回數據的,所以在刪除表的一定短時間內,來用這種方法來找回數據是可行的。若是時間過長,磁盤頁由於大量的IO操作,導致刷新了,有可能數據就被刷新掉了,這時候能不能找回數據,就不一定了。所以,在發現執行了誤操作後,應立即停止mysql,把數據磁盤掛載為只讀模式,避免數據頁被刷新。
使用undrop-for-innodb工具在無備份的情況下恢復mysql表