Linux

Linux 磁盘空间爆满排查实战

管某 5 分钟阅读

Linux 磁盘空间爆满排查实战


一、问题背景

磁盘空间不足是服务器最常见的运维故障之一。典型现象是 df -h 显示磁盘已用 100%,应用开始报 No space left on device,但用 du 逐目录查看时却找不到明显的大文件——“空间神秘消失”的情况往往最让人头疼。

本文整理了磁盘空间排查的完整思路,以及几个最经典的”隐藏空间”坑点。


二、基础排查

1. 确认磁盘占用情况

1
df -h
  • 定位是哪个挂载点已满
  • 关注 Use% 列和 Mounted on

2. 逐层定位大目录

1
du -h --max-depth=1 -x / | sort -rh | head -20
  • -x 表示不跨文件系统,避免统计到其他挂载点的内容
  • 从根目录逐层下钻,直到找到占用最大的目录
命令 作用
df -h 查看磁盘整体使用率
df -i 查看 inode 使用率
du -sh <目录> 统计指定目录总大小
find / -xdev -type f -size +1G 查找大于 1G 的单个文件

三、坑一:inode 耗尽

现象df -h 显示磁盘还有不少空间,但创建或写入文件时报 No space left on device

原因:小文件数量达到了文件系统的 inode 上限,空间还有,但”名额”用完了。

排查

1
df -i

IUse% 为 100% 即为 inode 耗尽。常见来源:

  • 邮件队列 /var/spool/postfix/maildrop/(大量退信小文件)
  • /tmp 下残留的临时文件
  • 程序运行时产生的海量小缓存文件

解决

1
2
3
4
5
# 统计哪个目录下小文件最多
find / -xdev -type f | awk -F/ '{NF--;print}' | sort | uniq -c | sort -rn | head -10

# 清理无用小文件后再确认
df -i

四、坑二:文件已删除但空间未释放

现象du 统计出的所有文件大小加起来,远小于 df 显示的已用空间。

原因:某个进程仍持有已删除文件的句柄。rm 之后空间并不会释放,要等进程关闭该文件(或进程退出)才会真正回收。

排查

1
2
3
4
5
# 查找所有被删除但仍被进程占用的文件
lsof | grep deleted

# 或查看指定进程打开的文件描述符
ls -l /proc/<PID>/fd/ | grep deleted

解决

1
2
3
4
5
# 方式一:重启或结束对应进程(推荐,如日志服务)
systemctl restart <服务名>

# 方式二:不重启,直接清空文件内容(如无用的日志文件)
: > /proc/<PID>/fd/<FD编号>

⚠️ 注意:不要对正在写入的日志文件直接 rm,同样的问题会再次出现,正确做法是 cat /dev/null > <日志文件> 或配置 logrotate。


五、坑三:systemd journal 日志

journald 默认会一直累积系统与服务的日志,是 /var 分区的隐藏空间大户。

排查

1
journalctl --disk-usage

立即清理

1
2
3
4
5
# 按总量限制清理
journalctl --vacuum-size=200M

# 或按时间清理(保留最近 7 天)
journalctl --vacuum-time=7d

永久限制:编辑 /etc/systemd/journald.conf

1
SystemMaxUse=200M

生效:

1
systemctl restart systemd-journald

六、坑四:Docker 容器日志

Docker 容器日志(/var/lib/docker/containers/ 下的 *-json.log)也是磁盘空间大户,其限制配置与清理脚本参见之前的文章:Docker日志过大的解决方案


七、其他容易被忽略的占用

位置 说明
/var/log/ 历史日志未做轮转,或 logrotate 配置失效
/var/spool/postfix/ 邮件队列堆积,同时吃磁盘和 inode
core dump 文件 程序崩溃产生的 core 文件,可用 find / -name "core.*" 查找
数据库日志 MySQL binlog、undo log 等未及时清理
/tmp/var/tmp 临时文件未设置自动清理

八、最佳实践

  1. 监控告警:部署磁盘使用率监控(如 Zabbix、Prometheus + node_exporter),建议阈值 85% 告警。
  2. 日志轮转:检查并配置 /etc/logrotate.conf/etc/logrotate.d/ 下的各服务配置。
  3. 限制日志上限:journald 配置 SystemMaxUse,Docker 配置 max-size / max-file(见 第 58 篇)。
  4. 定期巡检:写一个巡检脚本(df -hdf -ijournalctl --disk-usage)配合 crontab 定时执行并输出结果。

九、总结

磁盘排查遵循”先看 df,再挖 du,最后查 inode 和句柄“的思路:

现象 原因 关键命令
df 显示满但 du 对不上 已删文件仍被进程占用 lsof | grep deleted
有空间但写不进去 inode 耗尽 df -i
日志越滚越大 journald / Docker 未限制 journalctl --disk-usage

大部分”空间神秘消失”的问题都能用上面的方法定位,配合监控和日志限制可以避免再次发生。