磁盘显示已满但 du 找不到大文件?一次 lsof 排查实录

举报
yd_219479431 发表于 2026/11/03 10:50:35 2026/11/03
【摘要】  线上告警:df -h 显示根分区使用率 100%,但顺手执行 du -sh /* 把各目录累加一遍,总和只有 20 多个 G,跟 df 报的 45 G 完全对不上。空间到底去哪了?一、先搞清楚差异从哪来Linux 里“文件名”和“inode”是两件事。rm 做的只是 unlink:删掉目录项、把硬链接数减一。只要还有一个进程持有这个文件的描述符,inode 和它占用的数据块就不会被释放。于...

 线上告警:df -h 显示根分区使用率 100%,但顺手执行 du -sh /* 把各目录累加一遍,总和只有 20 多个 G,跟 df 报的 45 G 完全对不上。空间到底去哪了?

一、先搞清楚差异从哪来

Linux 里“文件名”和“inode”是两件事。rm 做的只是 unlink:删掉目录项、把硬链接数减一。只要还有一个进程持有这个文件的描述符,inode 和它占用的数据块就不会被释放。于是出现两个视角的分裂:

  • df 统计块设备的实际占用,这些“已删除但未释放”的块仍然算在里面;
  • du 是遍历目录树累加,文件已经没有目录项了,自然统计不到。

两者相减,就是被进程抱在怀里的那部分幽灵文件。常见诱因有三类:日志轮转配置不当、应用先删临时文件再继续写、以及一个 tail -f 挂在正在被清理的大日志上。

二、定位:一条命令看全

最直接的是 lsof,加 +L1 只列出硬链接数小于 1 的文件,也就是“已删除但还开着”的那批:

lsof +L1 | sort -k7 -n -r | head -20

精简镜像里往往没有 lsof,可以用 /proc 兜底:

find /proc/*/fd -ls 2>/dev/null | grep "(deleted)" | sort -k7 -n -r | head

输出第 7 列是大小,第 2 列是 PID,拿到 PID 后再用 ps -p <pid> -o pid,cmd 确认是哪个进程在写。

三、处理:别急着重启服务

如果这个进程不能随便重启(比如是生产服务),可以直接对它的 fd 做截断,空间立刻回收,进程继续持有这个被清空的“文件”:

: > /proc/<pid>/fd/<fdnum>

或者 truncate -s 0 /proc/<pid>/fd/<fdnum>。注意这是清空内容,如果里面还有你要的日志,先 cp /proc/<pid>/fd/<fdnum> /tmp/rescue.log 抢救一份再动手。

如果服务支持平滑重载,systemctl reload nginx 这类操作会让 worker 重新打开日志文件,是更干净的做法。

四、预防

  • logrotate 对无法 reopen 的应用使用 copytruncate,避免“删了还在写”。
  • 应用侧不要自己删日志文件,改成写固定路径、交给 logrotate 统一管理。
  • 把 df 与 du 的差值做成监控指标,超阈值直接告警,比等磁盘写满再救火体面得多。

小结:遇到 df 和 du 对不上,先怀疑“已删除未释放”,用 lsof +L1 定位,再用 truncate 或 reload 回收。整个过程不需要重启机器,也不会丢数据。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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