在Linux服务器运维过程中,rm -rf * 命令因其不可逆的破坏性始终伴随着高危风险。不同于桌面环境的回收站机制,该指令一旦执行将直接导致物理存储层面的数据删除。根据文件系统原理,即便使用专业恢复工具,成功恢复的概率仍与磁盘写入状态密切相关,这使得误操作极易造成永久性数据丢失。
下面是一次在Linux下对数据库执行rm -rf *后的恢复过程。涉及两个数据库共240张表,约5GB数据,数据库版本为MySQL 8.0.37。
过程:
一、文件恢复
1、查看打开这些文件的进程ID:
root@mysql-server:~# lsof -L |grep /data/mysql/data mysqld 272718 mysql cwd DIR 252,17 20480 14155778 /data/mysql/data mysqld 272718 mysql 10uW REG 252,17 12582912 14155781 /data/mysql/data/ibdata1 (deleted) mysqld 272718 mysql 12uW REG 252,17 12582912 14155787 /data/mysql/data/ibtmp1 (deleted) mysqld 272718 mysql 14uW REG 252,17 16777216 14155788 /data/mysql/data/undo_001 (deleted) mysqld 272718 mysql 15uW REG 252,17 16777216 14155792 /data/mysql/data/undo_002 (deleted) mysqld 272718 mysql 23uW REG 252,17 4315938816 14156109 /data/mysql/data/mydb/table_1.ibd (deleted) mysqld 272718 mysql 30uW REG 252,17 114688 14155959 /data/mysql/data/mydb/table_2.ibd (deleted) mysqld 272718 mysql 31uW REG 252,17 22020096 14156111 /data/mysql/data/mydb/table_3.ibd (deleted) mysqld 272718 mysql 32uW REG 252,17 27262976 14156171 /data/mysql/data/mydb/table_4.ibd (deleted)
2、查找进程文件描述符目录内容。
上面的第二列 272718 就是MySQL服务的进程ID,接下来找到进程对应的文件操作描述符目录 /proc/272718/fd,看一下内容:
root@mysql-server:~# cd /proc/272718/fd root@mysql-server:/proc/272718/fd# ll dr-x------ 2 mysql mysql 256 Nov 1 2023 ./ dr-xr-xr-x 9 mysql mysql 0 Nov 1 2023 ../ lr-x------ 1 mysql mysql 64 Mar 12 17:35 0 -> /dev/null l-wx------ 1 mysql mysql 64 Mar 12 17:35 1 -> '/var/log/mysql/error.log.1 (deleted)' lrwx------ 1 mysql mysql 64 Mar 12 17:35 10 -> '/data/mysql/data/ibdata1 (deleted)' lrwx------ 1 mysql mysql 64 Mar 12 17:35 106 -> '/data/mysql/data/mydb/table_1.ibd (deleted)' lrwx------ 1 mysql mysql 64 Mar 12 17:35 118 -> '/data/mysql/data/mydb/table_3.ibd (deleted)'
可以直接使用 cat 这些描述符来确定文件内容是否还在。
3、使用IO重定向进行恢复。
将文件恢复到本地,这里切勿和被恢复的文件放到相同的分区!!
# cat /proc/272718/fd/118 > /recovery/data/mysql/data/mydb/table_3.ibd
或者将数据流传输至其他服务器进行保存。
# cat /proc/272718/fd/118 | ssh 192.41.6.5 'cat > /data/recovery/data/mysql/data/mydb/table_3.ibd'
如果文件较多,可以结合awk sed或者记事本进行批量处理生成需要执行的重定向命令。
二、数据库恢复
要将恢复回来的ibd文件导入到新库上,要求新库的数据库表结构必须与ibd内的数据使用的表结构相同,否则是无法使用导入ibd的方式恢复(后面会讲怎么处理)。
1、创建并导入初始化用的数据库。
2、导入ibd数据
-- 禁用外键约束检查 SET FOREIGN_KEY_CHECKS = 0; -- 丢弃指定表的表空间 ALTER TABLE table_1 DISCARD TABLESPACE; ALTER TABLE table_2 DISCARD TABLESPACE; ALTER TABLE table_3 DISCARD TABLESPACE; -- 将恢复回来的ibd文件拷贝到对应的数据库下面,然后进行导入,过程中不需要重启数据库服务 -- 导入表空间 ALTER TABLE table_1 IMPORT TABLESPACE; ALTER TABLE table_2 IMPORT TABLESPACE; ALTER TABLE table_3 IMPORT TABLESPACE; -- 全部导入成功后重新启用外键约束检查 SET FOREIGN_KEY_CHECKS = 1;
3、处理无法导入的ibd
我遇到了4个表因为表结构问题致使无法导入ibd文件。接下来可以使用一个名为 ibd2sql 的开源工具,它可以从ibd文件中解析出sql语句。
该脚本基于Python编写,可以从ibd文件中解析出sql语句,不需要安装第三方库,使用方法如下:
# wget https://github.com/ddcw/ibd2sql/archive/refs/tags/v1.9.tar.gz # tar -zxvf ibd2sql-1.9.tar.gz # cd ibd2sql-* # cp /recovery/data/mysql/data/mydb/table_7.ibd . # python3 main.py ./table_7.ibd --sql --ddl > table_7.sql
接下来将生成的sql文件在目标数据库上执行,最后将整个恢复完的数据库导入到目标环境进行测试验证即可。
脚本 Release Notes 里介绍的是解析 MySQL 5.7 的ibd文件,但是我用在MySQL 8.0.xx的ibd文件上也可以顺利解析,可能是由于这几个表数据不复杂吧。
最后:
1、误删除文件切勿慌张,如果还存在访问该文件的进程,抓紧利用IO重定向的方法将数据备份出来;
2、做好每日备份,如果是云主机最好也要开快照;
3、执行rm操作时需格外谨慎,尽量避免使用rm -rf * 这样危险的命令;
4、感谢 ibd2sql 工具作者。
注:本次恢复成功存在较大偶然性,实际生产环境应建立多重数据保护机制,切勿依赖事后恢复。
本文结束。
Leave a comment