学完这篇,你能在十分钟内把被日志撑满的磁盘救回来,并配好自动轮转,让服务不再因为同一个原因第二次宕机。
第一步:先确认到底是不是磁盘满了
服务突然 502、SSH 登录报 No space left on device,八成就是磁盘满。登上去执行:
df -h
看哪个分区 Use% 是 100%,通常是 / 或 /var。接着定位是哪个目录吃掉的:
du -sh /var/log/* | sort -rh | head -20
如果 du 加起来只有几百 MB,但 df 显示满了,说明有文件被删了却还被进程占着句柄,用这条命令找:
lsof +L1 2>/dev/null | head -20
第二步:止血——清空文件,而不是删除文件
这一步的目标是立刻腾出空间让服务恢复。关键点是:日志文件正被 nginx/php-fpm 等进程打开着,直接 rm 不会释放空间,必须把文件内容截断:
truncate -s 0 /var/log/nginx/access.log
或者等价的写法:
: > /var/log/nginx/error.log
清完再 df -h 确认空间回来了,然后重启受影响的服务:
systemctl restart nginx
注意:如果你手快已经 rm 掉了文件,磁盘却没释放,用 lsof +L1 查到持有句柄的 PID,执行 systemctl restart <服务名> 或 kill -USR1 <PID> 让进程重新打开日志文件,空间才会真正还回来。
第三步:用 logrotate 做自动切割
logrotate 是绝大多数发行版自带的服务,配置文件放在 /etc/logrotate.d/ 下,一个服务一个文件。新建 /etc/logrotate.d/nginx,内容:
/var/log/nginx/*.log {
daily
rotate 7
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
endscript
}
含义是:每天切一次,保留 7 份,压缩旧文件,切完后给 nginx 发 USR1 信号让它重新打开日志文件。
注意:kill -USR1 这行不能省。nginx 支持信号重开日志,但很多程序不支持,那种情况要用 copytruncate 参数替代 postrotate,代价是切割瞬间可能丢几行日志。两种方式不要同时用。
改完先干跑一次验证语法:
logrotate -d /etc/logrotate.d/nginx
确认没有报错,再强制执行一次:
logrotate -vf /etc/logrotate.d/nginx
最后确认定时任务在跑:
systemctl status logrotate.timer
第四步:管住 systemd journal 这个隐形大户
很多人清完 nginx 日志发现空间没回来多少,因为 /var/log/journal/ 才是大头。限制它的上限,编辑 /etc/systemd/journald.conf:
SystemMaxUse=500M
SystemKeepFree=1G
MaxRetentionSec=2week
保存后重启:
systemctl restart systemd-journald
journalctl --vacuum-size=200M
注意:journalctl --vacuum-size 只清旧日志,配置里的 SystemMaxUse 才是长期生效的阀门,两者都要做。
第五步:加一道监控,别等宕机才发现
写个简单脚本 /usr/local/bin/check_disk.sh:
#!/bin/bash
THRESHOLD=85
df -h | awk 'NR>1 {gsub("%","",$5); if ($5 > '"$THRESHOLD"') print $6" 使用率 "$5"%"}'
挂到 crontab 每 5 分钟跑一次,有输出就发邮件或推送到企业微信机器人:
*/5 * * * * /usr/local/bin/check_disk.sh | mail -s "磁盘告警" ops@example.com
注意:阈值别设 95%,那时候日志已经写不进去了。85% 告警,留出处理时间。
第六步:治本的几个方向
- 把 nginx 的
access_log 级别调低,或者用 map 指令丢掉静态资源的记录,日志量能降一半以上。
- 多台机器的话,用 rsyslog 把日志转发到独立的日志服务器(
*.* @loghost:514),本机只留最近几小时。
- 应用层把 debug 级别的日志关掉,
log_level 从 debug 改成 warn。
小结
- 磁盘满先用
df -h 定位分区,du -sh 和 lsof +L1 定位文件。
- 清日志用
truncate -s 0,不要 rm;删了没释放就重启进程。
- logrotate 配
/etc/logrotate.d/ 下的规则,nginx 记得 kill -USR1 重开日志。
- journald 要在
/etc/systemd/journald.conf 里设 SystemMaxUse,不能只靠 vacuum。
- 监控阈值设 85%,别等到 100% 才告警。