Linux 服务器磁盘空间不足是非常常见的运维问题。磁盘满了之后,服务可能无法写日志,数据库无法落盘,容器无法启动,甚至 SSH 登录也会变慢。排查这类问题时,关键是先定位哪个分区满了,再逐层找出占用空间最大的目录和文件。

本文整理一套常用排查流程,适用于大多数 Linux 服务器。

查看磁盘分区使用情况

首先使用 df 查看各分区空间:

1
df -h

输出示例:

1
2
3
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1 40G 38G 2.0G 95% /
/dev/vdb1 200G 120G 80G 60% /data

重点关注 Use% 和挂载点。如果 / 根分区接近 100%,很多系统组件都会受到影响。

查看 inode 使用情况:

1
df -ih

如果磁盘空间还有,但 inode 用完,也会出现无法创建文件的问题。大量小文件、缓存文件和临时文件可能导致 inode 耗尽。

找出大目录

从满的挂载点开始排查。例如根分区满了:

1
du -h --max-depth=1 / 2>/dev/null | sort -h

如果 /var 很大,继续:

1
du -h --max-depth=1 /var 2>/dev/null | sort -h

常见大目录包括:

  • /var/log:系统和应用日志。
  • /var/lib/docker:Docker 镜像、容器、日志和 volume。
  • /tmp:临时文件。
  • /home:用户上传、编译产物、缓存。
  • /var/lib/mysql:数据库文件。

du 统计目录实际占用,df 统计文件系统使用情况。二者不一致时,可能存在已删除但仍被进程占用的文件。

查找大文件

查找超过 1GB 的文件:

1
find / -xdev -type f -size +1G -print 2>/dev/null

-xdev 表示不跨文件系统,避免从根分区排查时进入其他挂载盘。

查看文件大小排序:

1
find /var -type f -printf '%s %p\n' 2>/dev/null | sort -nr | head -20

如果系统不支持 -printf,可以使用:

1
find /var -type f -size +500M -exec ls -lh {} \; 2>/dev/null

删除文件前一定要确认文件用途。数据库文件、业务上传文件、正在写入的日志都不能随意删除。

清理日志文件

查看日志目录:

1
du -h --max-depth=1 /var/log | sort -h

systemd 日志可以查看占用:

1
journalctl --disk-usage

清理到只保留最近 7 天:

1
journalctl --vacuum-time=7d

或限制总大小:

1
journalctl --vacuum-size=1G

普通日志如果确认可以清理,推荐截断而不是直接删除正在写入的文件:

1
truncate -s 0 /var/log/app.log

直接 rm 一个正在被进程打开的日志文件,磁盘空间可能不会立刻释放,因为文件描述符仍然被进程持有。

查找已删除但仍被占用的文件

如果 df 显示空间满,但 du 找不到对应大文件,检查 deleted 文件:

1
lsof | grep deleted

可能看到类似:

1
java 1234 app 10w REG /var/log/app.log (deleted)

这表示文件已经被删除,但进程还在写。解决方式通常是重启对应进程,或让进程重新打开日志文件。

如果是线上服务,重启前要评估影响,优先使用平滑重启或日志 reload 机制。

Docker 占用排查

Docker 常占用 /var/lib/docker。查看整体占用:

1
docker system df

清理未使用镜像、容器、网络和构建缓存:

1
docker system prune

如果确认可以清理未使用 volume:

1
docker system prune --volumes

注意 volume 可能保存数据库或上传文件,执行前必须确认不会删除重要数据。

容器日志过大时,查看:

1
find /var/lib/docker/containers -name '*-json.log' -size +500M -exec ls -lh {} \;

临时截断:

1
truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log

长期方案是配置 Docker 日志轮转。

清理包管理缓存

Ubuntu/Debian:

1
2
apt-get clean
apt-get autoremove

CentOS/RHEL:

1
yum clean all

这些命令通常风险较低,但仍建议在维护窗口执行,避免和正在运行的软件安装任务冲突。

建立长期治理

临时清理只能解决一次问题。长期应做好:

  • 日志轮转,例如 logrotate。
  • Docker 日志大小限制。
  • 监控磁盘使用率和 inode。
  • 将数据库、上传文件、备份文件放到独立数据盘。
  • 定期清理构建缓存和临时目录。
  • 对大文件目录设置容量告警。

logrotate 示例:

1
2
3
4
5
6
7
8
/var/log/myapp/*.log {
daily
rotate 14
compress
missingok
notifempty
copytruncate
}

copytruncate 适合不支持 reopen 日志文件的应用,但高并发写日志时可能丢少量日志。更好的方式是让应用支持日志切割信号。

小结

磁盘空间排查可以按固定顺序进行:df -h 定位分区,du 找大目录,find 找大文件,lsof 检查 deleted 文件,再针对日志、Docker、缓存和业务数据分别处理。删除前必须确认文件用途,线上服务优先选择截断、轮转和配置治理,而不是临时手工删除。