凌晨三点,手机连着震了五下。我眯着眼看了一眼,全是同一台机器的磁盘告警:/ 使用率 92%,94%,96%,98%,99%。五分钟一条,眼看着就要满了。

这不是第一次了。上周刚处理过一台机器日志写满盘的,那次是 inode 耗尽,几十万个碎日志文件。这次又来了,我心想,怎么老跟日志过不去。

我套上外套往电脑前跑,一边跑一边想:昨天下午还看过 df,才 61%,怎么一夜之间涨了快 40 个点?

登录上去先 df -h 确认,果然,/ 已经 99%。再 du -sh /* 一个个看,最后定位到 /var/log,占了 40 多个 G。

进去一看,好家伙,一个 nginx 的 access.log 已经 23G,error.log 也有 9G。但最狠的不是它,是 /var/log/messages,17G。messages 这文件平时一天也就几 MB,17G 意味着有东西在疯狂往系统日志里刷。

tail -f /var/log/messages 看了十秒,刷了几百行,全是同一行重复:

systemd[1]: Failed to start xxx.service.
systemd[1]: Unit xxx.service entered failed state.

一个服务反复拉起、反复失败,每失败一次 systemd 记一条,一晚上刷了 17G。

我 kill 掉那个服务,先让日志停下来,然后 truncate 清掉大文件——注意是 truncate 不是 rm,rm 的话跑着的进程还握着 fd,空间根本不会释放,这个坑我踩过不止一次。

truncate -s 0 /var/log/messages
truncate -s 0 /var/log/nginx/access.log
truncate -s 0 /var/log/nginx/error.log

df 一看,空间回来了,99% 掉到 34%。

然后才是正经事:那个服务为什么反复失败?systemctl status 一看,报错是配置文件里写了个不存在的路径,大概率是昨天谁改配置改坏了。查了修改时间,确实是昨天下午。改回来,systemctl start,起来了,日志安静了。

处理完已经快四点。我坐在那想,这事的教训其实不是"日志会写满盘",而是:

第一,日志该有轮转。nginx 的 logrotate 是配了的,但 messages 这种系统日志没人管,配个 logrotate 把 messages 也轮起来,限制大小和保留天数,就不会出现 17G 这种事。

第二,失败重试要有上限。那个服务配了 Restart=always,失败了就无限重启,每次重启都刷一条日志。改成 Restart=on-failure + RestartSec,再配合 StartLimitBurst,失败几次就放弃,别让它在深夜里自己跟自己较劲。

第三,磁盘告警阈值太低了。90% 才告警,从 61% 涨到 90% 中间那么长时间没人知道。改成 80% 告警一次,85% 再告一次,给处理留出缓冲。

改完这些,天都亮了。我躺回床上,手机又震了一下,我心脏一紧,拿起来一看,是早上六点的天气推送。

吓死我了。