logrotate日志轮转实战:Nginx、PHP与应用日志自动切分清理


一、为什么日志必须轮转而非无限膨胀

服务器上 Nginx、PHP、MySQL、应用自己的日志,若任由其增长,几个月就能吃掉几十 GB 磁盘,轻则磁盘告警、重则分区写满导致服务崩溃。logrotate 是 Linux 自带的日志管理工具,它按时按量对日志做"切分 + 压缩 + 清理 + 重载服务",把日志维护变成自动化。几乎所有主流发行版都默认带 crontab + logrotate 日报,我们只需把规则写好,它每天自动执行。

二、logrotate 工作原理与主配置

logrotate 通过"配置文件 + 每日定时任务"运作:logrotate -d 可调试,主配置需按设定频率运行。默认由 crontab 驱动(/etc/cron.daily/logrotate),也可手动执行:

# 手动执行(-f 强制轮转,-d 不真正执行只演示,-v 显示过程)
sudo logrotate -dv /etc/logrotate.conf
sudo logrotate -f /etc/logrotate.conf

核心配置项都放在 /etc/logrotate.conf,自定义规则建议写进 /etc/logrotate.d/。自定义规则优先级高于默认段,新增规则无需改主文件、便于管理和备份。

三、为 Nginx 配置日志轮转

在 /etc/logrotate.d/nginx 写一条规则,分钟轮转频率由 daily/weekly 决定:

/var/log/nginx/*.log {
    daily                    # 每天轮转一次
    rotate 14                # 保留最近 14 份
    compress                 # 轮转后 gzip 压缩
    missingok                # 文件不存在不报错
    notifempty               # 空日志不轮转
    dateext                  # 用日期命名,如 access.log-20260928
    sharedscripts            # 下面脚本只在所有日志轮转完后执行一次
    postrotate
        [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
    endscript
}

关键点是 `postrotate` 里的指令:Nginx 打开日志文件后不会再重新打开同名字符串,必须发送 `USR1` 信号让它重新打开新日志文件,否则日志会被反复写进同一个已轮转的文件,甚至因删除句柄而中断记录。sharedscripts 确保这个"重载"动作只在全部日志处理完毕后执行一次,而不是每个文件都执行。

四、PHP-FPM 与应用日志配置

PHP-FPM 日志、应用自己输出的日志同样可以管理:

# /etc/logrotate.d/php-fpm
/var/log/php-fpm.log /var/log/php-fpm-slow.log {
    daily
    rotate 14
    compress
    missingok
    notifempty
    create 0640 www-data www-data   # 轮转后以指定权限重建新日志
    postrotate
        [ ! -f /run/php/php8.2-fpm.pid ] || kill -USR2 `cat /run/php/php8.2-fpm.pid`
    endscript
}

# /etc/logrotate.d/myapp  自定义应用日志
/var/log/myapp/*.log {
    weekly
    rotate 4
    compress
    missingok
    notifempty
    copytruncate            # 先复制再清空,避免重启应用也能轮转
}

`copytruncate` 适用于"无法通过信号重载日志"的应用:先复制当前日志为旧文件,再把原文件截断为空。它的代价是复制瞬间可能丢掉极少量记录,但对那些不提供日志重载信号的应用是必要手段。能用 postrotate 重载信号的应用优先用信号方式。

五、压缩、清理与大小阈值

compress                 # gzip 压缩旧日志
compresscmd /usr/bin/gzip
delaycompress            # 轮转后不立即压缩,留一份供追查
size 100M                # 按大小触发:达到 100M 即轮转(与 daily 可同时写)
maxsize 100M             # 到达大小即轮转,避免单份过大
age 7                    # 至少 7 天前的旧日志才轮转

`delaycompress` 配合 postrotate 重载很有用:轮转当天保留未压缩的旧日志,便于当天排错,第二天再压缩。size 与 daily 同时存在时按"先到先触发"执行;想"每天且超 100M 才轮转"应改用 maxsize,语义更符合直觉。

六、排错与避坑建议

# 调试:只预览将执行的操作,不真正轮转
sudo logrotate -d /etc/logrotate.d/nginx
# 强制轮转并显示详细输出
sudo logrotate -vf /etc/logrotate.d/nginx
  • 轮转没生效:检查 /etc/cron.daily/logrotate 权限(需可执行)、用 -d 排查规则是否匹配到文件。
  • 日志写进旧文件:多半是没配 postrotate 重载 Nginx/PHP-FPM,补上信号即可。
  • error: stat of failed:日志路径不存在,加 missingok 容忍。
  • 磁盘仍满:rotate 份数 + 单份大小相乘估算占用,别把天数据留太多天。
  • 权限问题:logrotate 通常以 root 跑,但 `create` 可指定新建日志属主,避免 Web/PHP 用户写不动。

写在最后

logrotate 是"花十分钟配置、长期受益"的后台工程。核心就三件事:为每种日志写一条规则(频率、保留份数、压缩)、必要服务的 postrotate 重载信号、以及用 -d/-v 调试验证。不建议把所有日志一股脑套用同一套参数——Nginx/PHP 重载信号各有差异,应用日志可能要走 copytruncate。配好后,磁盘空间与日志文件就不会再成为你半夜惊醒的理由。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

LVM磁盘扩容实战:逻辑卷在线扩容、加PV扩容与文件系统扩展

WireGuard加密隧道组网实战:密钥配置、全隧道分流与排错指南

评 论
更换验证码