最常见原因是已删除但进程仍打开的文件;df统计文件系统块级占用,du仅统计目录树中可见文件,故rm后若进程持有句柄,空间不释放,导致df显示100%而du总和极小。

磁盘显示满但 du 找不到大文件,大概率不是磁盘坏了,也不是 du 失效,而是空间被“看不见”的东西占着——最常见的是已删除但进程仍打开的文件。
为什么 df 显示 100% 但 du 统计总和很小
df 看的是文件系统块级占用,du 看的是目录树下“能被遍历到”的文件。一旦文件被 rm 删除,但某个进程(如 nginx、java、rsyslogd)还持有着它的文件描述符,内核就不会回收磁盘块。此时 df 认为它还在用,du 却再也找不到它的路径了。
其他常见干扰项包括:
-
inode耗尽(df -i查看),尤其在大量小文件场景(如缓存、session、邮件队列) - 挂载点覆盖:比如
/data原本有旧文件,后来挂了新磁盘,那些文件就被“遮住”了,du /data统计的是新磁盘,不是根分区原空间 -
/run/log/journal或/var/log/journal被systemd-journald无节制写满(journalctl --disk-usage可验证) - Docker 的
overlay2层残留(/var/lib/docker/overlay2下的diff或merged目录中存在未清理的层)
用 lsof 定位 deleted 状态文件
这是解决“空间失踪”的第一关键动作。不要跳过这步直接删日志或重启服务。
执行以下命令之一:
lsof +L1
或更精准地过滤根分区:
lsof / | awk '$5=="REG" && $9!="?" && $11~/deleted/ {print $1, $2, $9, $11}'
输出类似:
nginx 12345 /var/log/nginx/access.log deleted
说明 nginx 进程(PID 12345)仍在往一个已被删除的 access.log 写入。这时空间不会释放。
操作建议:
- 优先尝试平滑 reload:
nginx -s reload或systemctl reload nginx,多数日志服务支持,不中断连接 - 若进程不支持 reload(如某些 Java 应用),且业务允许,再
kill -9 12345 - 极端情况可清空 fd 内容:
echo '' > /proc/12345/fd/7(需先ls -l /proc/12345/fd/找到对应 fd 编号)
别漏掉 journal 和 overlay2 这两个“静默吃空间大户”
这两类问题不会出现在 du /* 结果里,但能轻松吞掉几十 GB:
-
systemd-journal:默认不限大小,
journalctl --disk-usage查当前用量;临时清理用journalctl --vacuum-size=500M;永久限制需改/etc/systemd/journald.conf中的SystemMaxUse=500M并systemctl restart systemd-journald -
Docker overlay2:运行
docker system df -v看镜像、容器、卷的实际占用;确认无用容器后,docker system prune -a(慎用,会删所有停止容器和未使用镜像);若只想清理 dangling 层:docker builder prune或手动进/var/lib/docker/overlay2查diff目录大小(需停 dockerd)
检查挂载点覆盖和 inode 耗尽
这两个问题容易被忽略,但排查极快:
- 运行
mount或findmnt,看是否有非标准挂载点(如/var/log、/home被单独挂载)。若有,临时umount /xxx(确保业务允许),再du -sh /xxx看是否藏着大文件 - 运行
df -i,若某分区IUse%达到 100%,说明 inode 耗尽。用find /var -xdev -type f | cut -d/ -f1-3 | sort | uniq -c | sort -nr | head -10定位小文件密集目录,再针对性清理(如清空/var/spool/postfix/maildrop或/tmp下过期 session)
真正棘手的从来不是“找不到文件”,而是找到之后不敢动——比如你发现是数据库 binlog 或容器日志占满,却不确定删了会不会丢数据。这种时候,先确认备份状态,再决定是 truncate、rotate 还是扩容。











