Logrotate 是几乎所有 Linux 发行版预装的服务,负责按时间或大小对日志做日志轮转:自动切分、压缩、删除旧日志,防止单个日志无限增长把磁盘打满。很多线上故障并不是代码写错,而是 /var/log 下某个日志悄悄长到几十 GB,把系统盘塞爆。本文从原理到实战,手把手配出一套可靠、可调试、可回滚的日志轮转策略。
为什么必须做日志轮转
一个长期运行的服务,访问日志、错误日志、审计日志会持续累加。如果从不轮转,后果不止”磁盘空间变少”这么简单:日志文件越大,后续写入越慢;磁盘写满后新请求无法落盘,进程开始报错甚至崩溃;更隐蔽的是 inode 也可能先被海量小日志耗尽,导致”磁盘还有空间却无法创建文件”。这和磁盘 inode 耗尽排查、磁盘 IO 被打满是同一类根治问题——而日志轮转,正是最省心的第一道防线。
Logrotate 是怎么被触发的
Logrotate 本身是个一次性命令,真正”每天跑一次”靠的是调度器。传统发行版把它放在 /etc/cron.daily/logrotate,由 cron/anacron 每天触发;使用 systemd 的系统则提供 logrotate.service 与 logrotate.timer,由定时器每日唤起。无论哪种方式,它启动时都会读取主配置 /etc/logrotate.conf,再逐个加载 /etc/logrotate.d/ 目录下的片段——所以绝大多数场景,你只需要在 /etc/logrotate.d/ 里新增一个文件,而不要去动主配置。
# 查看定时器是否启用(systemd 系统)
systemctl status logrotate.timer
# 手动触发一次(生产排障常用)
/usr/sbin/logrotate /etc/logrotate.conf
# 查看今天是否已执行(anacron 记录)
cat /var/lib/logrotate/status
第一个配置:轮转 Nginx 访问日志
以 Nginx 为例,新建 /etc/logrotate.d/nginx。下面这套配置覆盖了 90% 的 Web 服务场景:每天轮转、保留 14 份、压缩旧日志、丢失文件不报错、空文件不轮转,并在轮转后通知 Nginx 重新打开日志文件。它和Nginx 反向代理配置、服务器安全加固共同构成一台对外服务主机的运维基线。
/var/log/nginx/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
create 0640 www-data adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
endscript
}
这里最关键的是 postrotate 里的 kill -USR1:Nginx 收到 USR1 信号会重新打开日志文件描述符,否则它还会继续往已被重命名的旧文件里写,轮转就失去了意义。用 systemctl reload nginx 也能达到同样效果,但 reload 比 USR1 重一点,高并发场景更推荐 USR1。
关键指令速查
理解下面这张表,就能应对绝大多数轮转需求。指令写在小节的花括号内,对当前小节的所有日志文件生效。
| 指令 | 作用 | 常见取值 |
|---|---|---|
| daily / weekly / monthly | 按时间周期轮转 | 每天 / 每周 / 每月 |
| rotate N | 保留几份旧日志 | 7 / 14 / 30 |
| size / minsize / maxsize | 按体积触发(见下文) | 100M / 50M / 200M |
| compress / nocompress | 是否用 gzip 压缩旧日志 | compress |
| delaycompress | 延迟一轮再压缩,兼容正在写的进程 | delaycompress |
| copytruncate | 拷贝后截断原文件,无需重载服务 | copytruncate |
| create [mode owner group] | 轮转后新建日志并指定权限 | create 0640 root utmp |
| missingok | 日志不存在也不报错 | missingok |
| notifempty | 空文件不轮转 | notifempty |
| dateext / dateformat | 用日期而非序号命名旧日志 | dateext |
| olddir | 把旧日志放到别的目录 | olddir /var/log/archive |
按大小还是按时间:size / maxsize / minsize 的区别
这是最容易配错的一组。三者都和体积有关,但触发逻辑完全不同:
# size:只要超过 100M 立刻轮转,不管时间周期
size 100M
# maxsize:超过 100M 或到了 daily 周期,先到先轮
daily
maxsize 100M
# minsize:必须 daily 周期到了,且体积超过 50M 才轮
daily
minsize 50M
经验法则:访问日志用 daily + maxsize 最稳,既不会因突发流量撑爆磁盘,也不会因清淡期无意义地天天切;审计类低频日志用 size 更合适,只有真的写大了才动它。
应用没有”重开日志”信号怎么办:copytruncate
有些老程序或第三方组件不会响应 USR1,也不会在配置 reload 后重开日志。这种情况用 copytruncate:先复制当前日志内容到轮转文件,再把原文件截断为 0 字节。进程始终写同一个文件描述符,不需要任何信号,代价是复制与截断之间可能丢失极少量日志(毫秒级)。
/var/log/myapp/app.log {
daily
rotate 10
size 200M
copytruncate
compress
missingok
notifempty
}
用 postrotate 正确重载服务
sharedscripts 表示只有当本小节至少有一个文件被轮转时,才执行一次 postrotate(避免每个文件都 reload 一次服务)。下面以 Java 服务为例,用 systemd 重新打开日志:
/opt/myapp/logs/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
copytruncate
sharedscripts
postrotate
systemctl reload myapp.service > /dev/null 2>&1 || true
endscript
}
让旧日志带日期:dateext
默认轮转出的文件叫 nginx.log.1、nginx.log.2.gz,序号不直观。加上 dateext 后会变成 nginx.log-20261102.gz,一眼能看出是哪天产生的,也方便和备份策略对齐。
/var/log/app/*.log {
daily
rotate 30
dateext
dateformat -%Y%m%d
compress
delaycompress
missingok
notifempty
create 0640 app app
}
调试:先 dry-run 再强制
千万别直接改完配置就等明天自动跑——先用 -d 做”干跑”,它会完整模拟轮转过程并打印每一步,但不真正改动任何文件,是上线前必做的验证。
# 干跑:只打印将要做什么,不修改文件
logrotate -d /etc/logrotate.d/nginx
# 强制立即执行一次(verbose 看明细),用于验证效果
logrotate -vf /etc/logrotate.d/nginx
# 只跑某一个,不影响其它配置
logrotate -vf /etc/logrotate.conf
-d 输出里重点看两处:是否”considering log”后进入了轮转分支,以及 postrotate 脚本是否被正确解析。若看到 error: 则说明配置语法有问题,需要先修。
常见排障
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 日志从没被轮转 | 配置语法错或文件权限不对 | logrotate -d 看 error;确认 /etc/logrotate.d/ 下文件权限 644 |
| 磁盘还是被写满 | 用了 size 但阈值太大,或没配 compress | 调小 maxsize、确认 compress 生效 |
| 轮转后服务不写新日志 | 忘了 postrotate 重载,或用了 copytruncate 之外却截断 | 加 kill -USR1 或 systemctl reload;评估 copytruncate |
| 旧日志权限错误 | create 的 owner/group 写错 | 用 create 指定正确的属主,或加 su 指令 |
| SELinux 下轮转失败 | 新文件安全上下文不对 | 用 semanage 修正类型,或配合 olddir 同分区 |
和监控、容器配合
轮转解决”历史日志堆积”,但”实时磁盘水位”仍需监控兜底。把磁盘使用率接入 Prometheus + Grafana 监控面板,在 80% 水位就报警,比等写满再救火从容得多。容器场景下,日志最好交给 Docker 的 logging driver 或节点级 logrotate 统一接管,避免容器内部自己写盘、又没人轮转的”双重失控”。
总结
Logrotate 看似只是个”切日志”的小工具,却是 Linux 服务器长期稳定运行的隐形基石:用 /etc/logrotate.d/ 下的片段化管理配置,靠 daily + maxsize + compress + delaycompress 兜住体积,用 postrotate 信号或 copytruncate 适配不同服务,再用 logrotate -d 干跑验证后再上线。把它和 inode 监控、磁盘 IO 监控、Prometheus 告警串起来,日志就再也成不了压垮服务器的那根稻草。下次部署新服务时,记得把”配好日志轮转”写进你的上线检查清单。




