运维踩坑记:磁盘空间突然报满 (No space left on device) 怎么破?
昨晚凌晨两点,报警系统疯狂弹窗:某台核心业务服务器的接口大量返回 500 错误。
紧急登录服务器查看,发现业务进程全挂了,敲个 tab 键补全命令都提示:No space left on device。
老运维一听就知道,磁盘被撑爆了。今天复盘一下处理这种紧急故障的”三板斧”。
第一斧:锁定罪魁祸首 (df 与 du 的配合)
首先运行 df -h 确认是哪个挂载点满了。通常是 / 根目录。
1 | df -h |
接着,我们要找出是谁吃掉了空间。回到根目录,运行这行极其好用的命令:
1 | du -sh /* 2>/dev/null | sort -hr | head -n 10 |
这会列出当前目录下占用空间最大的前 10 个文件夹。一路追踪下去,我发现是 /var/log/nginx/ 目录竟然有 80GB!
1 | du -sh /var/log/nginx/* |
第二斧:小心”幽灵文件”
找到大日志文件后,很多新手的操作是:rm -rf access.log。
这是致命的错误! 如果 Nginx 进程还在运行,并且持有着这个文件的句柄,你用 rm 删除后,磁盘空间是不会释放的!(俗称幽灵文件或被删除但未释放的文件)。
原因是 Linux 的文件系统设计:只有当所有引用该文件的进程都关闭后,inode 才会真正被释放。用 lsof 可以找到这些幽灵文件:
1 | lsof | grep deleted | awk '{print $1, $2, $7}' | sort -rn | head |
正确的清空正在被使用的文件的方法是:
1 | cat /dev/null > /var/log/nginx/access.log |
瞬间,磁盘空间释放,报警解除,服务恢复。
第三斧:别忽略了 inode 耗尽
磁盘空间满了还比较好解决。但有一种更隐蔽的情况——磁盘还有空闲空间,但系统依然报 No space left on device。
这极有可能是 inode 耗尽了。每个文件系统有固定数量的 inode,每个文件和目录都会消耗一个。当你运行了一些会产生海量小文件的服务(比如邮件队列缓存、session 文件等),inode 会先于磁盘空间用完。
检查 inode 使用率:
1 | df -i |
找出哪个目录有海量小文件:
1 | for dir in /*; do |
第四斧:systemd journal 占用
现在的 Linux 发行版大多使用 systemd 管理日志,它默认将日志持久化到磁盘。如果配置不当,也可能吃掉几十 GB:
1 | journalctl --disk-usage |
第五斧:Docker 磁盘清理
如果你在服务器上运行 Docker,它的 overlay2 存储驱动也会在不知不觉中吞掉大量空间:
1 | docker system df # 查看 Docker 占用 |
第六斧:治本之策 (Logrotate)
故障虽然排除了,但这完全是”人祸”。生产环境的日志绝不能让它无限膨胀。必须配置 Linux 自带的 logrotate 工具进行日志按天切割并压缩。
为 Nginx 创建 logrotate 配置:/etc/logrotate.d/nginx
1 | /var/log/nginx/*.log { |
关键参数说明:
rotate 14:保留最近 14 天的日志compress/delaycompress:压缩但延迟一天,避免影响当天日志写入postrotate:切割后给 Nginx 发送信号,让它重新打开日志文件
建立监控告警
人不可能 24 小时盯着服务器。最后的防线是自动化监控:
1 | # 一个简单的磁盘空间告警 cron 脚本 |
总结
磁盘空间问题的排查是运维的必修课。从 df/du 定位元凶,到处理幽灵文件,再到 logrotate 根治问题,每一步都需要冷静和准确的判断。记住:凌晨两点的服务器不会等你,但一个好的运维预案会。
