服务器磁盘满了:一套从报警到定位的排查顺序

举报
yd_292915714 发表于 2026/11/07 12:25:15 2026/11/07
【摘要】 df 显示满了但 du 对不上?先分清容量还是 inode,再逐层下钻目录,最后用 lsof 查已删除仍被占用的文件。附 Docker/日志/包缓存三大户的清理边界和一个可复用脚本。

服务器磁盘满了:一套从报警到定位的排查顺序

磁盘告警是最常见也最容易慌的一类故障。很多人第一反应是 rm -rf 找地方删东西,结果删错文件或者删了没释放空间。下面这套顺序是实测下来最省时间的:先定位分区,再定位目录,再定位文件,最后才动手清理。

第一步:确认是哪个分区满了

df -h

看 Use% 那一列,不要只看 /。常见的坑是根分区还有空间、但 /var/lib/docker 或 /data 单独挂载的分区满了,服务写不进去照样报错。

如果 df 显示已用 100%,但你怎么也找不到大文件,先看 inode:

df -i

IUse% 满了同样会报 "No space left on device",但原因不是容量而是小文件太多(常见于邮件队列、session 文件、缓存目录)。

第二步:定位到目录,不要全盘扫

sudo du -x --max-depth=1 / 2>/dev/null | sort -rh | head -15

-x 很关键:它让 du 不跨文件系统,否则挂载的 NFS、docker overlay 都会被算进根分区,数字完全失真。

找到最大的目录后,逐层往下钻,每次只加一层:

sudo du -x --max-depth=1 /var | sort -rh | head -10
sudo du -x --max-depth=1 /var/lib | sort -rh | head -10

比一次性 du -a / 快得多,因为不需要遍历整棵树。

第三步:按文件大小排序

sudo find /var -xdev -type f -size +200M -printf '%s\t%p\n' 2>/dev/null \
  | sort -rn | head -20 | awk '{printf "%.1fG\t%s\n", $1/1073741824, $2}'

-xdev 同样是不跨文件系统的意思。注意有些精简系统(比如容器里的 busybox/toybox)的 find 不支持 -printf,那就退化成:

sudo find /var -xdev -type f -size +200M -exec ls -lh {} \; | awk '{print $5, $9}' | sort -rh | head -20

第四步:判断是不是「删了但没释放」

这是最容易被忽略的一种:df 显示满了,du 加起来却对不上。

原因是进程还持有已删除文件的句柄。文件在目录树里没了,但 inode 没释放,空间继续被占。

sudo lsof +L1 2>/dev/null | head -20

或者更直接:

sudo lsof | grep deleted | awk '{print $1, $2, $7, $9}' | sort -k3 -rn | head -10

处理方式不是再删文件,而是让持有它的进程重新打开日志(多数服务支持 SIGHUP 或重启),空间才会真正归还。

第五步:常见的几个「空间大户」

按出现频率排:

1. Docker

docker system df

RECLAIMABLE 那列是可回收量。清理要分清对象:

docker image prune -f                 # 悬空镜像,安全
docker builder prune -f               # 构建缓存,安全
docker system prune -f                # 会删停止的容器和未使用网络,需确认

不要随手 docker volume prune,命名卷里可能是数据库数据。

2. 日志

sudo journalctl --disk-usage
sudo du -sh /var/log/* 2>/dev/null | sort -rh | head -10

journald 限制大小:

sudo journalctl --vacuum-size=500M

/etc/systemd/journald.conf 里设 SystemMaxUse=500M 可以长期生效。

应用日志建议用 logrotate,而不是写个 cron 定时 rm——后者会把正在写的文件句柄搞成 deleted 状态,反而占着空间。

3. 包管理器缓存

sudo du -sh /var/cache/apt /var/cache/dnf /var/cache/yum 2>/dev/null
sudo apt-get clean       # Debian/Ubuntu
sudo dnf clean all       # RHEL/Fedora

4. 旧内核

Debian 系:

dpkg -l | grep linux-image | awk '{print $2, $3}'
sudo apt-get autoremove --purge

清理时的三条纪律

1. 先看再删:ls -lh 确认文件是什么,别对着路径猜。

2. 不要删正在写的文件:日志类用 truncate -s 0 或 logrotate,直接 rm 会造成 deleted 占用。

3. 删完复查:df -h 和 df -i 都看一遍,确认真的降下来了,别只看一个。

一个可复用的排查脚本

#!/bin/bash
# 磁盘占用快查:分区 / 目录 / 大文件 / deleted 句柄
echo "===== 分区使用率 ====="
df -h | awk 'NR==1 || $5+0>80'

echo "===== inode 使用率 ====="
df -i | awk 'NR==1 || $5+0>80'

echo "===== 根分区一级目录 TOP10 ====="
du -x --max-depth=1 / 2>/dev/null | sort -rh | head -10

echo "===== 大于 200M 的文件 TOP10 ====="
find / -xdev -type f -size +200M -exec ls -lh {} \; 2>/dev/null \
  | awk '{print $5, $9}' | sort -rh | head -10

echo "===== 已删除但仍被占用的文件 ====="
lsof +L1 2>/dev/null | awk 'NR>1 {print $1, $2, $7, $9}' | sort -k3 -rn | head -10

把它放在 /usr/local/bin/disk-check 里,出问题时一条命令就能看到全貌,比一条条试命令快得多。

小结

  • 先 df -h 和 df -i,分清是容量满还是 inode 满
  • du -x --max-depth=1 逐层下钻,别全盘扫
  • lsof +L1 查「删了但没释放」
  • Docker、日志、包缓存是最常见的三个大户
  • 日志用 truncate/logrotate,不要直接 rm
  • 清完两个 df 都复查
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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