磁盘满了怎么查:从 df 到 du,再到那个删了也不释放的文件

举报
yd_242458115 发表于 2026/10/26 10:43:01 2026/10/26
【摘要】 df 显示 100% 但 du 加起来只有一半?这是运维最经典的坑之一。这篇把磁盘占用的四级排查路径讲清楚:分区、目录、文件、以及已经被删除但还被进程攥着的句柄。

服务器突然写不进文件,日志停了,数据库报错。第一反应都是敲 df -h,看到某个分区 100%,然后开始删日志。

但有一类情况会让人卡很久:df 说满了,du 加起来却只有一半。

这篇把磁盘占用的排查拆成四级,从粗到细,最后一级是最容易漏的。

第一级:看分区,确认是哪个盘满了

df -h

输出里的 Use% 是判断依据。注意两点:

一是看清楚挂载点。很多人在根分区上删了半天,实际满的是 /var 或 /data 这种独立挂载的分区。

二是注意 inode。有些文件系统会因为 inode 耗尽而无法创建新文件,但空间还有富余:

df -i

如果 IUse% 是 100% 而空间没满,那就是小文件太多——常见于缓存目录、session 文件、邮件队列。这种情况删大文件没用,得删大量小文件。

第二级:找大目录,缩小范围

du -h --max-depth=1 / 2>/dev/null | sort -rh | head -20

--max-depth=1 只看第一层,sort -rh 按人类可读的大小倒排。这样能快速定位到是哪个顶层目录在膨胀。

确定了大方向后再往下钻:

du -h --max-depth=2 /var | sort -rh | head -20

一层层往下,通常三五轮就能定位到具体目录。

注意 2>/dev/null:不加这个会刷出一堆权限不足的报错,把有用信息淹掉。

第三级:找大文件

定位到目录后,直接按大小排序找文件:

find /var/log -type f -size +100M -exec ls -lh {} \; | sort -k5 -rh | head -20

或者用 du 加排序:

du -ah /var/log | sort -rh | head -20

日志是最常见的大头。如果发现某个日志文件已经几个 G,别急着 rm——正在写的日志文件被删掉,句柄还开着,空间不会释放(这就是第四级要讲的)。

正确做法是清空内容而不是删除文件:

: > /var/log/某个应用.log

或者用 truncate:

truncate -s 0 /var/log/某个应用.log

这样文件还在,写入方不受影响,空间立刻释放。

第四级:df 和 du 对不上的时候

这是最经典、也最容易卡住人的情况:

df -h        # 显示 / 已用 100%
du -sh /*    # 加起来只有 50%

差了将近一半。原因是:有文件已经被删除了,但仍然被某个进程打开着。

Linux 的规则是:文件被 unlink(删除目录项)后,如果没有进程持有它的句柄,空间才真正释放。如果有进程还开着这个文件(比如一个不停写日志的服务,日志文件被 rm 掉了),那块空间就一直被占着,du 看不到它(因为它已经没有目录项了),但 df 会算进去。

怎么找出来

lsof +L1

+L1 的意思是"列出 link count 小于 1 的文件"——也就是已经被删除、但还有进程开着的文件。

如果机器上没装 lsof,可以直接翻 /proc:

ls -l /proc/*/fd/* 2>/dev/null | grep deleted

输出里会显示类似 ... -> /var/log/app.log (deleted),前面是进程 pid 和文件描述符编号。

怎么解决

找到进程 pid 后,有几种处理方式,按安全程度排序:

最安全:重启那个服务。 进程重启后句柄释放,空间自动回来。

次安全:只让进程重新打开日志文件。 很多服务支持信号通知:

kill -USR1 <pid>

不少守护进程收到 USR1 会重新打开日志文件(logrotate 就是这么工作的)。但不同程序行为不同,用之前查一下它的文档。

最后手段:kill -9。 会丢数据,除非确认那是个可以随便杀的东西。

千万别做的:手动去 /proc/<pid>/fd/<n> 上做 truncate。这个操作在某些内核版本上行为诡异,可能把文件指针搞乱,导致进程后续写入错位。真要用也得先停服务。

一个预防习惯

排查完把根因修掉,否则下周还会来一次:

  • 日志不轮转 → 配 logrotate,按大小或日期切分并保留 N 份
  • 临时文件堆积 → 加一条定时清理,注意排除正在使用的
  • 容器日志无限增长 → 给 docker 配 max-size 和 max-file,否则 /var/lib/docker 会把盘吃干净
  • 数据库 binlog 不清理 → 设置保留天数

小结

排查顺序记成一句话:df 找分区 → du 找目录 → find 找文件 → lsof +L1 找幽灵。

最后一级是分水岭。会用 lsof +L1 的人,遇到"删了不释放"能十分钟解决;不会的人,可能会重启整台机器,甚至以为磁盘坏了。

一个提醒:排查期间不要急着 rm。先看清楚谁占着、为什么占着,再动手。删文件是最简单的一步,也最容易白删。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。