你的网站是不是被日志文件“撑爆”了?

磁盘突然告急?df -h一看,/var/log占了98%?
查了半天,发现一个 access.log 已经长到 40GB——而你连上周三的 404 错误都找不到。

日志轮转到底是什么?为什么非做不可?

日志轮转,就是让日志自己“按时下班、打包存档、腾出空位”。

它不复杂:每天(或每小时)把正在写的日志关掉,改个名字,压成 .gz,再新建一个空文件接着记。整个过程自动完成。

没它会怎样?
→ 磁盘越攒越多,直到某天 nginx 写不了日志,直接报错挂掉;
→ 查问题时翻不到三天前的日志——因为早被覆盖了;
→ 想分析流量高峰?抱歉,只有最新一小时的碎片。

真实场景:去年帮一家本地 SaaS 公司排查慢响应,发现他们 Apache 的 access.log 跑了半年没轮转,单文件超 80GB。一重启服务,光是打开日志文件就卡住 3 秒——这哪是记录访问,这是给服务器上刑。

主流的日志轮转方案有哪些?

首选 logrotate ——Linux 服务器上最稳、最熟、最不用操心的方案。它不是某个软件的插件,而是系统级工具,Nginx、Apache、自研 Python 服务、甚至你写的 shell 脚本日志,它全都能管。

Web 服务器自带的轮转(比如 Nginx 的 reopen_logs)也能用,但功能太简陋:不能压缩、不能按日期命名、没法设保留份数。真要靠它扛生产流量,等于拿订书机当电钻使。

至于容器环境?如果你用 Docker,别急着上 Fluentd。先确认一件事:你的应用是否真的必须“边写边轮转”?多数中小团队的 PHP/Node/Java 应用,老老实实用 logrotate 配合宿主机定时任务,更轻量、更可控、出问题更好 debug。

如何用 logrotate 配置一个“黄金标准”?

配置文件放在 /etc/logrotate.d/ 下,名字随便起(比如 nginx-access),内容如下:

/var/log/nginx/access.log {
    daily
    rotate 30
    missingok
    notifempty
    compress
    delaycompress
    dateext
    sharedscripts
    create 0640 www-data www-data
    postrotate
        [ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
    endscript
}

关键项直白解释:

  • daily:每天凌晨切一次;
  • rotate 30:最多留 30 天的归档(access.log-20241001.gz 这种);
  • compress + delaycompress:旧日志压成 .gz,但最新一份先留着明文,方便紧急排查;
  • dateext:归档名带日期,不怕顺序乱;
  • create 0640 www-data www-data:新日志文件一生成,权限和属主就设好,避免 nginx 写不进去;
  • postrotate 里的 kill -USR1:通知 Nginx “换新本子记账”,不中断服务。

配置时最容易踩的坑是什么?

坑一:新日志文件 nginx 写不进去
logrotate 默认用 root 创建文件,但 nginx 是 www-data 用户跑的。结果新日志属主是 root,权限 600,nginx 直接被拒之门外。
✅ 解法:加上 create 0640 www-data www-data,一步到位。

坑二:轮转后,日志还在往旧文件里写
postrotate 脚本执行失败(比如 pid 文件路径错了),logrotate 不报错,但 nginx 没收到信号,继续往 access.log-20241001 这种已归档的文件里狂写。
✅ 解法:手动跑一遍 sudo logrotate -f /etc/logrotate.d/nginx-access,然后立刻 ls -l /var/log/nginx/,确认新 access.log 出现且大小在涨。

坑三:磁盘还是满了
你以为 rotate 7 + compress 就只占 7 份空间?忘了 delaycompress 会让当天的旧日志先留明文,加上压缩延迟,高峰期可能同时存在 access.logaccess.log-20241001access.log-20241001.gz 三份。
✅ 解法:给 /var/log 单独划个分区,或者至少留出 2 倍于日均日志量的缓冲空间。

怎么验证和监控日志轮转是否正常?

别等出事才想起来看。配置完马上验证:

  1. 先用 -d 参数“纸上谈兵”:
    sudo logrotate -d /etc/logrotate.d/nginx-access
    
    它会打印每一步打算做什么,语法错、路径错、权限错,全给你标出来。
  2. 再用 -f 强制执行一次:
    sudo logrotate -f /etc/logrotate.d/nginx-access
    
    然后 ls -lt /var/log/nginx/,看到 access.log-YYYYMMDD.gz 生成,且新的 access.log 时间戳是刚更新的,就齐活了。

监控不用花哨:
→ 把 /var/log 所在分区的使用率,加进你已经在用的 Zabbix 或 Prometheus;
→ 设置告警阈值 85%,比等它爆满强十倍;
→ 顺手 grep "logrotate" /var/log/syslog | tail -10,每月扫一眼有没有 error 关键字。

今天下班前就能完成的具体操作

别收藏吃灰。现在就打开终端,按这五步走:

  1. 定位日志:执行 du -sh /var/log/* | sort -hr | head -5,找出前三大的日志目录;
  2. 新建配置:运行 sudo vim /etc/logrotate.d/myweb
  3. 粘贴模板:把下面这段复制进去,把 /var/log/nginx/access.log 换成你的真实路径,把 www-data 换成你服务的实际用户(比如 nginxapache2):
    /var/log/nginx/access.log {
        daily
        rotate 14
        compress
        delaycompress
        dateext
        missingok
        notifempty
        create 0640 www-data www-data
        postrotate
            [ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
        endscript
    }
    
  4. 立即测试:先 sudo logrotate -d /etc/logrotate.d/myweb 看输出是否干净;再 sudo logrotate -f /etc/logrotate.d/myweb,然后 ls -lt /var/log/nginx/ 确认新归档出现;
  5. 加进监控:打开你熟悉的 Zabbix 或 Prometheus 页面,找到“磁盘使用率”监控项,把 /var/log 所在挂载点加进去,阈值设为 85%。

做完这五步,今晚睡觉前,你服务器的磁盘压力就少了一块大石头。