Linux 运维

df 显示 100%,但 du 加起来只有一半——这种「账对不上」的情况,多半是被删掉却仍被进程占用的文件。本文按排查顺序整理一套固定动作。

第一步:确认是哪块盘

df -hT          # 带文件系统类型,看 Use% 那一列
df -i           # 如果这里满了,那是 inode 而不是容量

df -i 经常被忽略。小文件极多时(比如缓存目录塞满了几十万个碎片文件),容量还剩很多但 inode 已经耗尽,新文件一律创建失败。

第二步:找出大目录

du 从根目录扫会非常慢,建议逐层下钻:

# 只看当前层,按大小排序,别加 -sh 那样会把子目录合并掉
du -h --max-depth=1 / | sort -rh | head -20

锁定最大的目录后,进入它重复上一条命令,通常三四层就能定位到元凶。

第三步:处理「已删除但被占用」的文件

如果 dudf 差距很大,用 lsof 找被删但仍被打开的文件:

lsof -nP | grep deleted | sort -k7 -rn | head -20

典型输出是一堆日志文件。这些空间只有等持有它的进程退出才会真正释放。不要去 kill -9,正确做法是通知对应进程重新打开日志:

# Nginx:直接发信号即可,不会中断连接
nginx -s reopen

# 或者用 logrotate 手动跑一次
logrotate -f /etc/logrotate.d/nginx

第四步:确认释放结果

df -h /        # 空间应当立刻回落

顺手加一个告警

与其等它满了再救火,不如让脚本提前说话:

#!/bin/bash
THRESHOLD=85
USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')

if [ "$USAGE" -ge "$THRESHOLD" ]; then
    echo "磁盘使用率 ${USAGE}%,请检查" | mail -s "磁盘告警" ops@example.com
fi

配合 crontab 每小时跑一次,基本就不会再遇到半夜磁盘写满的事了。

小结

固定顺序:df -hTdf -idu --max-depth=1 逐层下钻 → lsof | grep deleted。前三步解决 90% 的问题,第四步解决剩下那 10% 里最迷惑人的一类。

参与讨论