Linux 磁盘空间忽高忽低怎么办?从 df、du 到已删除文件句柄排查

Linux 服务器磁盘空间告警很常见,但有一种情况特别容易让人误判:监控里磁盘使用率一会儿很高、一会儿又降下来;或者 df -h 显示空间快满了,du -sh 却找不到对应的大文件。遇到这种问题,不要急着删除目录,也不要第一时间重启业务。先判断空间到底被谁占着,才能避免把正常日志、缓存或业务数据误删。

Linux 服务器磁盘空间排查与日志分析
磁盘空间排查不要只看一个数字,要把文件系统、目录占用和进程句柄放在一起判断。

这篇文章按实际排障顺序,把 dfdu、已删除文件句柄、日志轮转、临时目录和容器写入几个常见原因串起来。读完后,至少能做到三件事:知道磁盘空间为什么会“看起来忽高忽低”;知道哪些命令适合先查;知道什么时候该清理、什么时候该让服务释放句柄。

先确认是哪块盘在变

排查前第一步,是确认告警来自哪个挂载点,而不是笼统地说“服务器磁盘满了”。Linux 里根目录、数据盘、日志盘、Docker 数据目录可能分别挂在不同位置。常用命令是:

df -h
lsblk
findmnt

df -h 看的是文件系统层面的已用空间和可用空间,适合判断哪个挂载点紧张;lsblk 可以看磁盘和分区关系;findmnt 能确认目录实际落在哪个挂载点上。比如 /var/home/data 分别在不同分区时,不能只盯着根目录看。

如果只有某个业务目录所在分区上涨,问题通常集中在日志、上传文件、缓存、备份或容器层;如果根分区整体上涨,则要重点看 /var/log/tmp、包管理缓存、系统日志和 Docker 默认目录。先把范围缩小,后面才不会乱翻全盘。

df 和 du 为什么对不上

很多人会用下面两个命令交叉确认空间:

df -h /
du -xhd1 / 2>/dev/null | sort -h

df 统计的是文件系统已经分配出去的块;du 统计的是目录树里还能看到的文件大小。正常情况下,两者不会完全一样,但差距通常不至于特别离谱。如果 df 显示用了很多空间,而 du 在目录里找不到大文件,就要怀疑三类情况:文件已被删除但仍被进程占用、挂载点遮蔽了原目录内容、或者快照/特殊文件系统让统计口径不同。

其中最常见的是“已删除文件句柄”。例如 Nginx、PHP、Java、MySQL 或某个业务进程正在写日志,运维人员手动删除了日志文件,目录里确实看不到文件了,但进程还握着旧文件句柄继续写。此时空间不会真正释放,df 仍然显示占用很高,直到进程关闭该句柄。

检查已删除但仍占用的文件

判断这类问题,常用 lsof

lsof +L1
# 或者只看某个挂载点相关进程
lsof | grep deleted

如果看到某个进程后面带着 (deleted),并且文件大小很大,就说明空间被一个已经删除但仍打开的文件占住了。此时不建议直接杀进程,尤其是数据库、消息队列、核心业务服务。更稳妥的做法是先确认进程用途,再选择重新打开日志、平滑重载或在低峰期重启服务。

例如 Nginx 日志被删除后,可以优先尝试:

nginx -s reopen
# systemd 环境也可以按服务实际配置执行 reload
systemctl reload nginx

如果是应用进程写出的日志,要看应用是否支持日志重开、配置重载或进程内日志切割。只有确认没有安全替代方案时,才考虑重启服务。线上服务器最忌讳看到 deleted 就一把梭 kill -9,空间可能释放了,业务也可能跟着断。

日志轮转和压缩也会制造波动

磁盘空间忽高忽低,还可能来自日志轮转。logrotate 在切割、压缩、保留历史日志时,会短时间产生额外文件;如果某些服务没有正确重新打开日志,新旧日志还可能同时占用空间。建议检查:

logrotate -d /etc/logrotate.conf
ls -lh /var/log
journalctl --disk-usage

logrotate -d 是调试模式,不会真正执行轮转,适合检查规则是否命中。对于 systemd journald,还要看 journalctl --disk-usage,必要时通过 /etc/systemd/journald.conf 设置 SystemMaxUseSystemMaxFileSize 等限制,而不是长期放任日志自然增长。

需要注意,日志清理要优先用服务认可的方式处理。比如压缩旧日志、清理过期归档、调整保留天数,都比直接删除当前正在写入的日志安全。若网站业务比较依赖稳定性,也可以把日志目录、上传目录和数据库目录分盘规划,避免单个日志异常把整个系统盘拖满。

别忽略临时文件、缓存和容器层

除了日志,/tmp、应用缓存、构建产物、备份文件和容器镜像层也经常造成空间波动。可以按挂载点逐层查看:

du -xhd1 /var 2>/dev/null | sort -h
du -xhd1 /var/lib 2>/dev/null | sort -h

如果服务器运行 Docker,重点看:

docker system df
docker ps -a --size

容器日志也是高频原因,尤其是应用把大量访问日志、错误堆栈直接打到标准输出时,Docker 的 json 日志文件可能快速膨胀。清理前要先确认哪些容器、镜像、卷仍在使用,不能简单执行大范围删除。对生产环境来说,更推荐提前配置日志大小限制,例如 max-sizemax-file,让问题在告警前被控制住。

清理前先做风险判断

磁盘快满时,最危险的动作不是慢,而是删错。清理前至少确认四件事:文件是否属于当前业务;是否有备份;是否正在被进程使用;删除后服务是否需要重载或重启。对于数据库目录、上传目录、证书目录、站点代码目录,不要只凭文件名判断用途。

比较安全的处理顺序是:先删除确认无用的临时文件和旧压缩日志;再处理包管理缓存、构建缓存、过期备份;然后调整日志轮转和应用日志级别;最后才考虑扩容磁盘或迁移目录。若业务已经接近不可写状态,可以先临时释放少量安全空间,让数据库、Web 服务和监控恢复,再做细查。

如果是面向企业官网、跨境业务站点或客户系统的服务器,磁盘规划不要只按“当前文件大小”估算,还要预留日志、备份、缓存和增长空间。使用 速维云 这类云服务器承载业务时,也建议把系统盘、数据盘、备份策略和监控告警一起规划;例如中小型网站可以把代码、上传附件和数据库备份分目录管理,再结合快照或异地备份降低误删风险。

建立长期监控和预防策略

一次排障解决的是当下空间不足,长期稳定还要靠监控和策略。建议至少监控磁盘使用率、inode 使用率、目录增长速度、日志目录大小、Docker 占用和数据库备份大小。只监控 df 使用率是不够的,因为 inode 耗尽、单目录暴涨、已删除文件句柄都可能绕过直觉判断。

告警阈值也不要只设一个 90%。更实用的方式是分层:70% 提醒观察增长趋势,80% 检查可清理项和扩容计划,90% 进入应急处理。对于写入量大的业务,还可以增加“单位时间增长量”告警,比如 30 分钟内增长超过某个阈值就提示,避免等到磁盘真正打满才发现。

最后记住一个排障原则:df 告诉你文件系统有多满,du 告诉你目录里看得见的文件有多大,lsof 告诉你有没有看不见但仍被进程占用的空间。三者结合起来,才是排查 Linux 磁盘空间忽高忽低的完整起点。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享