Linux 磁盘明明满了,为什么 du 找不到大文件?一次真实排查记录
前几天登录服务器时,发现网站后台突然无法写入数据,上传文件也一直失败。最开始以为是目录权限问题,检查后才发现服务器磁盘已经满了。
执行:
df-h其中一个分区的使用率已经达到 100%:
Filesystem Size Used Avail Use% Mounted on /dev/vda1 40G 40G 0 100% /正常情况下,接下来应该用du查找占用空间较大的目录:
du-h--max-depth=1/2>/dev/null|sort-hr|head奇怪的是,du统计出来的文件总量只有二十多 GB,与df显示的 40GB 完全对不上。
这类问题通常不是df或du出错,而是某个文件虽然已经被删除,但仍被正在运行的进程占用。
一、df 和 du 为什么会出现不同结果?
df统计的是文件系统中已经被占用的磁盘块,而du统计的是当前目录中可以找到的文件。
如果一个日志文件正在被 Nginx、PHP、MySQL 或其他程序写入,此时直接删除该文件,目录中虽然已经看不到它,但进程仍然持有文件句柄。
只要对应进程没有关闭,磁盘空间就不会真正释放。
于是就会出现下面这种情况:
df -h显示磁盘已满;du -sh却找不到对应的大文件;- 重启服务器后空间又突然恢复。
二、查找已经删除但仍被占用的文件
可以使用lsof进行检查:
lsof+L1也可以使用下面这条命令:
lsof|grepdeleted如果服务器没有安装lsof,可以先安装:
CentOS、Rocky Linux:
yuminstall-ylsofUbuntu、Debian:
aptinstall-ylsof我当时看到的结果类似这样:
php-fpm 18642 www 5w REG 253,1 8589934592 0 524301 /www/logs/error.log (deleted)这表示 PID 为18642的 PHP-FPM 进程仍然占用着一个已经删除的日志文件,而且文件大小已经达到 8GB。
三、如何安全释放磁盘空间?
最稳妥的方法是重启占用该文件的服务,让进程关闭旧的文件句柄。
例如,文件被 Nginx 占用:
systemctl restart nginx被 PHP-FPM 占用:
systemctl restart php-fpm被 MySQL 占用:
systemctl restart mysqld具体服务名称可能因安装环境而不同,可以先查看正在运行的服务:
systemctl--type=service--state=running重启后再次执行:
df-h如果问题确实由已删除文件造成,磁盘空间一般会立即恢复。
生产环境中不建议看到进程就直接执行kill -9,因为这可能中断网站请求或数据库写入。最好先确认进程属于哪个服务,再选择重载或重启。
四、不能重启服务时怎么办?
如果业务暂时不能中断,可以通过/proc找到进程仍然打开的文件描述符:
ls-l/proc/18642/fd假设对应的文件描述符是5,可以检查它:
ls-lh/proc/18642/fd/5紧急情况下,可以清空这个文件描述符指向的内容:
truncate-s0/proc/18642/fd/5这种方法能够释放空间,但操作前必须确认 PID 和文件描述符,避免清空错误文件。普通场景下,重启对应服务仍然是更稳妥的处理方式。
五、避免问题再次发生
如果占用空间的是日志文件,应该配置日志自动切割,而不是等磁盘满了以后手动删除。
例如,可以检查/etc/logrotate.d/目录中的配置:
ls-l/etc/logrotate.d/也可以查看某个日志目录的大小:
du-ah/var/log|sort-hr|head-20建议同时设置磁盘使用率监控。当使用率达到 80% 或 90% 时提前告警,避免网站、数据库和队列任务同时受到影响。
总结
遇到df显示磁盘已满、du却查不到大文件时,可以按照下面的顺序排查:
- 使用
df -h确认分区使用率; - 使用
du查找正常存在的大文件; - 使用
lsof +L1查找已删除但仍被占用的文件; - 确认对应进程和服务;
- 重启服务释放文件句柄;
- 配置日志切割和磁盘告警。
这类问题在运行时间较长的 Web 服务器上并不少见。关键不是继续删除目录中的文件,而是找到仍然占用磁盘空间的进程。
文章标签:Linux、服务器运维、磁盘空间、lsof、日志管理