Linux 服务器磁盘空间不足怎么排查?df、du、日志清理与扩容一次讲清


网站突然打不开,SSH 登录后执行命令报 “No space left on device”,这是 VPS 用户最常见的故障之一。磁盘满了不仅写不进日志,MySQL 也可能直接拒绝写入,甚至导致数据库损坏。很多人第一反应是删文件,但删错位置不但没释放空间,还可能把业务数据一起删掉。这篇按“先定位、再清理、最后预防”的顺序讲清楚。

一、先确认哪个分区满了

df -h

重点看 Use% 和 Mounted on 两列。常见情况是根分区 100%,而数据盘还有空间。根分区满优先查 /var;数据盘满优先查网站目录、备份目录和上传目录。

顺便看一眼 inode:

df -i

如果 inode 使用率 100%,说明小文件太多,常见于 session 文件、缓存碎文件、邮件队列。这种情况删大文件没用,要按文件数量排查。

二、定位大目录:du 由浅入深

du -h --max-depth=1 / | sort -hr | head -20

找到最大的目录后逐层往下查,例如:

du -h --max-depth=1 /var | sort -hr | head

不要一上来就 du -h / 全盘扫描,IO 会飙高,网站会更卡。优先查 /var/log、/var/lib/docker、/www、/data、/root、/tmp 这几个位置,基本能覆盖九成情况。

三、最常见的几个“元凶”

  • 系统日志:journalctl --disk-usage 查看,长期不清理能占几个 G。
  • 网站日志:Nginx 的 access.log 在流量大或被刷时增长极快。
  • Docker:镜像层、停止的容器和 json-file 日志,docker system df 一看便知。
  • MySQL binlog:没设过期时间会一直累积。
  • 备份文件:本地备份没做轮转,越备越多。
  • 已删除但被占用的文件:rm 了空间没释放,进程还握着句柄。

四、清理日志的正确姿势

不要直接 rm 正在写入的日志,进程句柄还在,空间不会释放。正确做法是清空文件:

: > /var/log/nginx/access.log

journalctl 用自带命令限制体积更安全:

journalctl --vacuum-size=200M
journalctl --vacuum-time=7d

长期方案是改 /etc/systemd/journald.conf 里的 SystemMaxUse=200M,再执行 systemctl restart systemd-journald。

五、已删除文件仍占用空间

lsof +L1 | head -20

输出里能看到被删但仍打开的文件。处理方式是重启对应进程,比如 systemctl restart nginx,空间立刻释放。这也是“删了文件 df 还是 100%”的典型原因,不查这一步很容易白忙一场。

六、Docker 占用清理

docker system df
docker image prune -a
docker builder prune
docker system prune -a --volumes

注意最后一条会删掉未使用的数据卷,执行前确认没有业务数据在里面。生产机上更稳妥的做法是先 docker ps -a,把确实不用的容器和镜像单独删除,而不是无差别清理。

七、MySQL binlog 与备份

SHOW BINARY LOGS;
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;

更推荐在配置文件里设置 expire_logs_days=7,MySQL 8 用 binlog_expire_logs_seconds。备份文件则用脚本保留最近 7 天,旧文件自动删除,并尽量同步到对象存储,不要长期堆在系统盘上。

八、日志轮转:避免下次再满

Nginx 日志可以交给 logrotate 管理,在 /etc/logrotate.d/nginx 写入:

/var/log/nginx/*.log {
    daily
    rotate 14
    missingok
    compress
    delaycompress
    notifempty
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

logrotate 默认由 cron 每天执行,配置好后不用手动干预。Docker 容器日志则要在 daemon.json 里限制 max-size 和 max-file,这一项比事后清理有效得多。

九、扩容而不是一直删

如果清理完很快又满,说明容量确实不够。云厂商的云盘一般支持在线扩容,扩容后在系统里扩分区和文件系统:

growpart /dev/vda 1
resize2fs /dev/vda1        # ext4
xfs_growfs /               # xfs

LVM 则先 pvresize,再 lvextend -r。操作前务必创建快照,扩容命令敲错分区名是不可逆事故。

十、常见问题

  • df 和 du 结果差很多:大概率是已删除未释放的文件,用 lsof +L1 确认。
  • 删了日志空间没变:进程还持有句柄,清空文件或重启服务,而不是删除文件。
  • inode 满了:按目录统计文件数量,清理 session、缓存和临时文件。
  • 清完又满:查是否被刷日志、是否有死循环写日志、备份是否堆积。

总结

磁盘排查有固定顺序:df 找分区,du 找目录,lsof 找幽灵文件,再按日志、Docker、数据库、备份逐项清理。清理只是止血,真正要做的是日志轮转、容器日志限制、备份轮转和容量监控。把这四件事配好,磁盘满导致宕机的概率会低很多。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

网站被 CC 攻击怎么办?Nginx 限流、Cloudflare 与应急处理一次讲清

Docker 部署网站实战:安装、镜像、容器、数据卷与 Compose 一次讲清

评 论