根本原因是被删除但仍被进程占用的文件(unlinked but open),其inode未释放导致磁盘块无法回收;可通过lsof +L1或lsof / | awk过滤deleted状态定位,再按进程类型选择reload、kill或清理journal/docker资源。

df显示磁盘已满但du统计总和很小
这是最典型的“空间失踪”现象:运行 df -h 显示根分区使用率 100%,但用 du -sh /* 2>/dev/null | sort -h 扫描各目录,加起来远小于总容量。根本原因通常是:被删除但仍被进程占用的文件(unlinked but open)——它们的 inode 没被释放,磁盘块仍被锁住。
验证方法:lsof +L1(只显示链接数为 0 的打开文件),或更常用:lsof / | awk '$5=="REG" && $9!="?" && $11~/deleted/ {print $0}'。常见肇事者是日志服务(rsyslogd、journalctl)、Web 服务器(nginx、apache2)或长期运行的脚本重定向了 stdout/stderr 到已删日志文件。
检查 deleted 状态文件并释放空间
找到这类文件后,不能靠重启服务“碰运气”——有些进程不响应 HUP,有些甚至没有 reload 机制。必须精准操作:
- 确认进程是否可安全重启:
systemctl list-units --type=service --state=running | grep -E "(rsyslog|nginx|apache|docker)" - 若进程支持平滑 reload(如 nginx),优先执行:
nginx -s reload或systemctl reload nginx,这会关闭旧 fd 并打开新日志文件 - 若进程不支持或需立即释放,直接 kill 对应 pid:
kill -9 <pid></pid>(谨慎!确保业务允许中断) - 极端情况下(如 docker 容器内应用),可能需
docker exec -it <container> ls -l /proc/<pid>/fd/</pid></container>查看具体 fd 指向,再决定是否 stop 容器
警惕 /run/log/journal 和 /var/log/journal 占用
systemd-journald 默认不限制日志大小,尤其在频繁报错或调试模式下,/var/log/journal/ 可能无声无息吃掉数十 GB。它不会出现在 du /* 中,因为 journal 文件由 journald 独占管理,且部分日志可能还在内存或未刷盘。
快速清理:journalctl --disk-usage 查用量,journalctl --vacuum-size=500M 限制总大小,或 journalctl --vacuum-time=2weeks 清理旧日志。永久生效需编辑 /etc/systemd/journald.conf,取消注释并修改:SystemMaxUse=500M 和 MaxRetentionSec=2week,然后 systemctl restart systemd-journald。
检查隐藏挂载点和 overlayfs 层(Docker/K8s 场景)
在容器化环境中,df 显示的“已满”可能来自 overlay2 下层:/var/lib/docker/overlay2 里的 merged、diff、work 目录中存在大量未清理的 dangling layer。此时 du 扫描 /var/lib/docker 可能不准,因为部分目录被 mount 隐藏。
正确做法:docker system df -v 查看镜像、容器、卷的实际磁盘占用;清理无用资源:docker system prune -a --volumes(注意加 --volumes 才清卷);若发现某容器日志爆炸,可进其 /var/lib/docker/containers/<id>/<id>-json.log</id></id> 查看大小,并通过 docker update --log-opt max-size=10m --log-opt max-file=3 <container></container> 限流。
别忘了检查 /proc/mounts 或 findmnt,确认是否有 bind mount 或 tmpfs 挂载掩盖了真实路径——比如 /tmp 被挂成 tmpfs,但某个服务误把大文件写到 /var/tmp,而该目录又恰好被 bind 到一个已满的磁盘分区上。


















