昨晚凌晨两点,报警系统疯狂弹窗:某台核心业务服务器的接口大量返回 500 错误。

紧急登录服务器查看,发现业务进程全挂了,敲个 tab 键补全命令都提示:No space left on device

老运维一听就知道,磁盘被撑爆了。今天复盘一下处理这种紧急故障的”三板斧”。

第一斧:锁定罪魁祸首 (df 与 du 的配合)

首先运行 df -h 确认是哪个挂载点满了。通常是 / 根目录。

1
2
3
4
df -h
# 输出示例:
# Filesystem Size Used Avail Use% Mounted on
# /dev/sda1 50G 50G 0G 100% /

接着,我们要找出是谁吃掉了空间。回到根目录,运行这行极其好用的命令:

1
du -sh /* 2>/dev/null | sort -hr | head -n 10

这会列出当前目录下占用空间最大的前 10 个文件夹。一路追踪下去,我发现是 /var/log/nginx/ 目录竟然有 80GB!

1
2
3
du -sh /var/log/nginx/*
# 80G access.log
# 60G error.log

第二斧:小心”幽灵文件”

找到大日志文件后,很多新手的操作是:rm -rf access.log

这是致命的错误! 如果 Nginx 进程还在运行,并且持有着这个文件的句柄,你用 rm 删除后,磁盘空间是不会释放的!(俗称幽灵文件或被删除但未释放的文件)。

原因是 Linux 的文件系统设计:只有当所有引用该文件的进程都关闭后,inode 才会真正被释放。用 lsof 可以找到这些幽灵文件:

1
lsof | grep deleted | awk '{print $1, $2, $7}' | sort -rn | head

正确的清空正在被使用的文件的方法是:

1
2
3
cat /dev/null > /var/log/nginx/access.log
# 或者
truncate -s 0 /var/log/nginx/access.log

瞬间,磁盘空间释放,报警解除,服务恢复。

第三斧:别忽略了 inode 耗尽

磁盘空间满了还比较好解决。但有一种更隐蔽的情况——磁盘还有空闲空间,但系统依然报 No space left on device。

这极有可能是 inode 耗尽了。每个文件系统有固定数量的 inode,每个文件和目录都会消耗一个。当你运行了一些会产生海量小文件的服务(比如邮件队列缓存、session 文件等),inode 会先于磁盘空间用完。

检查 inode 使用率:

1
2
df -i
# 如果 IUse% 接近 100%,inode 用完了

找出哪个目录有海量小文件:

1
2
3
4
for dir in /*; do
count=$(find $dir -type f 2>/dev/null | wc -l)
echo "$dir: $count files"
done | sort -t: -k2 -rn | head -10

第四斧:systemd journal 占用

现在的 Linux 发行版大多使用 systemd 管理日志,它默认将日志持久化到磁盘。如果配置不当,也可能吃掉几十 GB:

1
2
3
4
5
6
journalctl --disk-usage
# 限制日志大小
vim /etc/systemd/journald.conf
# SystemMaxUse=500M
# SystemMaxFileSize=100M
systemctl restart systemd-journald

第五斧:Docker 磁盘清理

如果你在服务器上运行 Docker,它的 overlay2 存储驱动也会在不知不觉中吞掉大量空间:

1
2
3
docker system df          # 查看 Docker 占用
docker system prune -a -f # 清理无用的镜像、容器、网络和构建缓存
docker volume prune -f # 清理无用的数据卷

第六斧:治本之策 (Logrotate)

故障虽然排除了,但这完全是”人祸”。生产环境的日志绝不能让它无限膨胀。必须配置 Linux 自带的 logrotate 工具进行日志按天切割并压缩。

为 Nginx 创建 logrotate 配置:/etc/logrotate.d/nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 nginx adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}

关键参数说明:

  • rotate 14:保留最近 14 天的日志
  • compress / delaycompress:压缩但延迟一天,避免影响当天日志写入
  • postrotate:切割后给 Nginx 发送信号,让它重新打开日志文件

建立监控告警

人不可能 24 小时盯着服务器。最后的防线是自动化监控:

1
2
# 一个简单的磁盘空间告警 cron 脚本
*/30 * * * * [ $(df / | tail -1 | awk '{print $5}' | tr -d '%') -gt 90 ] && echo "Disk usage > 90%" | mail -s "DISK ALERT" [email protected]

总结

磁盘空间问题的排查是运维的必修课。从 df/du 定位元凶,到处理幽灵文件,再到 logrotate 根治问题,每一步都需要冷静和准确的判断。记住:凌晨两点的服务器不会等你,但一个好的运维预案会。