尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

一次心惊肉跳的服务器误删文件的恢复过程

一次心惊肉跳的服务器误删文件的恢复过程 一次心惊肉跳的服务器误删文件的恢复过程那天下午我正悠闲地喝着咖啡准备把刚写完的脚本部署到生产服务器上。一切看似平常直到我在终端里敲下那行命令——一个本该加--dry-run的删除命令我却直接执行了。几秒钟后屏幕上滚动出上百行“removed”字样我才猛然意识到我把/data目录下的核心业务数据删了个干净。那一刻咖啡杯差点摔在地上心跳直接飙到 140。这篇文章就是记录我从“事故现场”到“恢复成功”的全过程希望能给所有运维和开发同学提个醒。### 事故还原我是怎么“精准”误删的当时我在清理一个临时目录执行了类似这样的命令bash# 我本意是删除 /tmp/old_backup 下的临时文件# 但手滑多打了一个空格变成了删除 /data 下的所有文件rm -rf /data /tmp/old_backup# 注意/data 是业务数据目录/tmp/old_backup 是临时目录# 因为 /data 路径在前面系统先删除了 /data又删除了 /tmp/old_backup# 这行命令没有任何保护直接递归强制删除看到输出里出现了removed /data/orders.db我瞬间清醒。好在我没有立刻崩溃而是强迫自己冷静下来因为恢复数据的黄金时间往往就在几分钟内。### 第一步立刻停止写入挂载只读误删后最忌讳的是继续在同一个磁盘分区上做任何写操作。因为删除操作只是把文件的 inode 标记为“可用”并没有真正擦除数据块。如果你继续写入新文件系统可能会复用这些数据块那才是真正的“回天乏术”。我立刻执行bash# 1. 立刻卸载该分区如果无法卸载就挂载为只读umount /dev/sdb1 # 假设数据在 /dev/sdb1 上# 或者用只读方式重新挂载mount -o remount,ro /dev/sdb1 /data# 2. 检查分区状态确认没有进程在写入lsof D /data # 列出所有打开 /data 下文件的进程# 如果有进程还在写kill 掉或者通知业务方暂停这一步非常关键相当于给事故现场“拉起了警戒线”防止二次破坏。### 第二步用 debugfs 找回 inode 信息接下来我们可以用 Linux 自带的debugfs工具来查看被删除文件的 inode 信息。这种方法适用于 ext2/ext3/ext4 文件系统前提是你知道文件的大致路径和特征。bash# 用 debugfs 打开设备注意是设备文件不是挂载点debugfs /dev/sdb1# 在 debugfs 交互界面中查看被删除的文件lsdel /data# 这个命令会列出所有被删除但尚未被覆盖的 inode# 输出类似Inode 12345 is deleted, type is regular, mode is 0644, size is 2048lsdel 会列出 inode 号、文件类型、大小等信息。你可以根据大小和名称如果目录项还存在判断哪个是你需要的文件。### 第三步用 extundelete 自动恢复推荐如果你没有耐心手动用 debugfs 去拼接数据可以试试 extundelete 这个神器。它专门用于恢复 ext3/ext4 文件系统中被删除的文件。bash# 安装 extundelete以 Ubuntu 为例sudo apt-get install extundelete# 恢复整个 /data 目录下的所有文件到 /home/user/recovered/# 注意目标目录不要在要恢复的分区上避免覆盖sudo extundelete /dev/sdb1 --restore-directory /data --output-dir /home/user/recovered/# 如果知道具体文件名可以直接恢复单个文件sudo extundelete /dev/sdb1 --restore-file /data/orders.db --output-dir /home/user/recovered/如果运气好且磁盘没有被大量写入extundelete 会成功恢复大部分文件。我那次恢复出了 90% 的数据包括那个最重要的 orders.db 数据库文件。### 第四步如果没有 extundelete试试 grep 大法如果文件系统不是 ext 系列或者 extundelete 失效了还有一个“土办法”——直接从磁盘的裸设备上 grep 字符串。这种方法适合恢复文本文件或包含特定关键字的文件。python# 用 Python 读取整个磁盘设备搜索特定字符串# 注意这需要 root 权限且速度很慢适合小文件def recover_text_from_disk(device_path, search_string, output_file): with open(device_path, ‘rb’) as disk: # 分块读取避免占用太多内存 chunk_size 1024 * 1024 # 1MB offset 0 with open(output_file, ‘wb’) as out: while True: chunk disk.read(chunk_size) if not chunk: break # 在块内搜索字符串 if search_string.encode() in chunk: # 找到后把整个块写入输出文件 # 注意这只是一个简化的示例实际可能需要更精确的定位 out.write(chunk) print(f找到匹配写入 {output_file}偏移量 {offset}) offset chunk_size# 使用示例在 /dev/sdb1 上搜索 “BEGIN RSA PRIVATE KEY”私钥文件# recover_text_from_disk(‘/dev/sdb1’, ‘BEGIN RSA PRIVATE KEY’, ‘recovered_key.pem’)这个方法虽然笨拙但在某些场景下能救命。比如你误删了一个配置文件、私钥或者小脚本只要磁盘上的数据块没被覆盖就能通过搜索唯一字符串来恢复。### 第五步从备份恢复如果有的话如果你平时有做定时备份比如用 rsync、tar 或者云快照那恢复就简单多了。但要注意备份可能不是最新的会有一定数据丢失。bash# 假设你有每日备份到 /backup/data_20250101.tar.gz# 解压恢复到 /datatar -xzf /backup/data_20250101.tar.gz -C /data# 然后对比最新备份和当前数据的差异用日志或 binlog 补齐我那次因为没做备份是的我承认我偷懒了只能全靠 extundelete 硬扛。### 总结那次事故之后我总结了几个血的教训1.删除前必须加保护在生产环境执行rm -rf之前一定要用ls确认路径或者干脆改用trash-cli或safe-rm这类工具它们会把文件移动到回收站而不是直接删除。2.用--dry-run测试任何批量删除脚本先跑一遍--dry-run看输出再真正执行。3.备份是底线无论多忙核心数据必须有自动备份而且要定期测试恢复流程。4.误删后保持冷静第一时间停止写入然后按照“只读挂载 → debugfs/extundelete → 备份恢复”的顺序来操作。最终我恢复了 90% 的文件丢失了 10% 的临时日志影响不大但那次心跳加速的感觉至今难忘。技术再强也抵不过一次手滑。希望读到这里的你永远用不上这套恢复流程。
返回列表