服务器磁盘满了:一套从报警到定位的排查顺序
服务器磁盘满了:一套从报警到定位的排查顺序
磁盘告警是最常见也最容易慌的一类故障。很多人第一反应是 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 都复查
- 点赞
- 收藏
- 关注作者
评论(0)