磁盘满了别急着删库:df、du、inode 的三层排查法
磁盘满是最常见的线上故障之一,但「满了」只是结果。真正要先分清的是四种情况:大文件占满、文件已删除但被进程持有、inode 耗尽、以及某个目录被挂载覆盖。
分不清就删,容易删掉还在用的日志,或者删完 df 一点没变——因为空间被已删除的句柄占着。
先说结论
先 df -h 再看 df -i,最后 du 逐层定位。 如果 du 算出来很小而 df 显示满,八成是被删除但未释放的句柄。
- df -h 看分区,df -i 看 inode
- du -x --max-depth=1 / 找大目录(-x 不跨挂载点)
- lsof +L1 找已删除但仍被打开的文件
- 清理顺序:日志 → 缓存 → 大文件,别动数据库目录
先把问题说清楚
df 显示的是文件系统视角的已用块,du 统计的是目录树里可见文件的大小。两者不一致,通常意味着有文件被删除但进程还持有句柄。
另一种常见情况是 inode 用尽:小文件极多的目录(邮件队列、session 文件、临时文件)会把 inode 吃光,此时 du 看到的总量可能只有几个 G。
具体怎么做
按顺序执行,每步都验证完再进下一步:
- df -h 与 df -i 同时看一眼,先分清是空间问题还是 inode 问题
- du -x --max-depth=1 / | sort -h 找一级大目录,再逐层下钻
- lsof +L1 2>/dev/null 找已删除句柄,必要时重启对应服务释放
- 日志类优先用 truncate -s 0 清空,别直接 rm(服务还在写,句柄不释放)
- 清完再 df 复核,确认真的回收
参数与成本对照
把关键数值摊开,方便判断该选哪条路:
| 现象 | 典型原因 | 验证命令 |
|---|---|---|
| df 满、du 小 | 已删除文件仍被进程持有 | lsof +L1 |
| df -i 100% | 小文件过多 | df -i、find /path -type f |
| du 某目录很大 | 日志/备份/镜像堆积 | du -x --max-depth=1 |
| df 满但找不到大文件 | 挂载点被覆盖 | mount |

几个容易踩的坑
下面这些是最常见的错误做法:
- 直接 rm 大日志:句柄不释放,空间不会回来
- 删 /var/lib/mysql 里的文件:数据直接损坏
- 清 /tmp 时把正在用的 socket 删了,服务连不上
- 以为扩容就能解决,结果 inode 还是满的
最后补两句
磁盘告警应该做成监控项,而不是等它满了再救。阈值 80% 就介入,成本比抢救低得多。
工具是手段,理解机制才是能力。命令记不住没关系,知道「该看什么」就够了。
评论 (2)
lsof +L1 这招救过我一次,nginx 日志删了空间没回来,重启才释放。
inode 那条太真实,邮件队列堆了几百万个小文件,df -h 看着还有空间。
发表评论