误删生产环境 SQLite 数据库后的极限救援

在生产环境中,rm -rf 往往是运维人员的噩梦。今天,我误删了正在高频读写的 SQLite 数据库文件,但在重启服务前,通过 Linux 的 /proc 文件系统,成功将数据“起死回生”。

事故现场

背景:Docker 容器中的 API 网关服务使用 SQLite 作为元数据存储。
误操作:清理磁盘时误删了核心数据库文件 gateway.db
现状:文件在文件系统中已不可见,但 Docker 容器仍在运行。一旦重启服务,数据将永久丢失。

原理分析:为什么数据还能救?

Linux 下删除文件只是解除了目录项的链接。只要仍有进程持有该文件的句柄(File Descriptor),内核就不会释放磁盘空间,数据依然存在于磁盘上。

只要进程不死,数据就在。

救援三部曲

第一步:锁定进程 PID

找到容器在宿主机上的真实 PID:

docker inspect --format '{{.State.Pid}}' <container_id>
# 假设输出 PID 为 1496463

第二步:寻找“消失”的句柄

进入 /proc/<PID>/fd 目录,查找被删除的文件描述符:

ls -l /proc/1496463/fd | grep deleted
20 -> '.../gateway.db (deleted)'
21 -> '.../gateway.db-wal (deleted)'
22 -> '.../gateway.db-shm (deleted)'

关键点:SQLite 在 WAL 模式下,数据不仅存在于主文件,最新的事务数据在 -wal 文件里。忽略 -wal 会导致数据丢失。

第三步:通过句柄“复活”文件

直接使用 cp 命令将句柄复制出来:

mkdir -p /tmp/db_rescue

# 复制主文件、WAL 文件和 SHM 文件
cp /proc/1496463/fd/20 /tmp/db_rescue/gateway.db
cp /proc/1496463/fd/21 /tmp/db_rescue/gateway.db-wal
cp /proc/1496463/fd/22 /tmp/db_rescue/gateway.db-shm

验证与收尾

将三个文件放在同一目录下,SQLite 会自动合并 WAL 文件。

sqlite3 /tmp/db_rescue/gateway.db "SELECT count(*) FROM users;"

查询结果正常,数据完整无损!

复盘总结

  • Linux 机制rm 只是 unlink,引用计数不为 0 时数据不灭。
  • SQLite 特性:必须同时恢复 .db.db-wal.db-shm 文件。
  • 备份:虽然救回数据,但生产环境仍需依赖定期备份。

结论:误删不可怕,只要进程在,/proc 就是最后一道防线。

文章作者: 若海; 原文链接: https://www.rehiy.com/post/615/; 转载需声明来自若海观澜

添加新评论