日志切割后原文件仍占空间,说明服务进程仍在向已被重命名的旧文件写入,根本原因是logrotate未成功通知服务切换日志文件句柄;必须确保postrotate中包含有效信号(如kill -USR1或nginx -s reopen)并正确执行,且服务能响应该信号,否则轮转仅表面移动,实际写入持续发生。

日志切割后原文件仍占空间,说明服务进程还在往已被重命名的旧文件里写 —— 这不是 logrotate 没运行,而是它没通知到服务,或者服务没正确响应。
logrotate 轮转后旧文件还在增长?检查 postrotate 是否生效
logrotate 只负责移动、压缩、创建新空文件,postrotate 块才是让服务切换到新日志的关键。如果这里失败或被跳过,进程会继续往 /var/log/nginx/access.log.1(或类似已重命名的旧路径)里追加内容。
- 确认配置中是否写了
postrotate+ 有效通知逻辑,比如kill -USR1 `cat /var/run/nginx.pid`或systemctl kill --signal=SIGUSR1 nginx - 检查该命令能否手动执行成功:运行一遍,再立刻
ls -l /proc/$(cat /var/run/nginx.pid)/fd/ | grep access.log,看 fd 指向的是不是新文件 - 务必在
postrotate末尾加|| true或重定向错误(如2>/dev/null),否则某次信号发不出就会静默中断整个轮转流程 - 注意 SELinux 或 systemd 的
PrivateTmp=yes可能导致/var/run/nginx.pid实际不可读,改用systemctl show --property MainPID nginx获取 PID 更可靠
服务不支持 USR1/SIGHUP?试试 copytruncate 或 create 指令
某些老服务(如部分 Java 应用、自研脚本)根本不监听重载信号,postrotate 发信号等于白发。这时不能靠“通知”,得靠 logrotate 主动接管写入行为。
-
copytruncate:先复制日志内容到新文件,再清空原文件。原 fd 不变,服务无感知,但存在极小概率丢最后一段写入(毫秒级) -
create 0644 user group:轮转后新建空文件并设好权限。前提是服务必须每次写日志前都重新 open(),否则仍会往旧 fd 写 - 二者不可共存;
copytruncate更稳妥,但不适用于超大日志(复制耗时+磁盘 I/O 峰值) - 若用
copytruncate,别配postrotate—— 它已无意义,还可能干扰
轮转后空间还是没释放?马上查 lsof +L1
即使 logrotate 配置正确,也可能因进程卡死、信号未送达、或容器内 PID 命名空间隔离,导致旧文件实际仍在被写。此时 df -h 和 du -sh 差值会明显拉大。
- 直接运行:
lsof +L1 /var/log(限定路径更快),找带(deleted)标记且 size 很大的行 - 重点关注
FD列(如1w、2w),那是正在写的写入句柄 - 对应 PID 查服务:
ps -fp 12345或systemctl status --all | grep 12345 - 不要
kill -9;优先systemctl reload nginx或kill -USR1 12345(查文档确认信号类型)
为什么 maxsize 触发轮转后,旧文件还在涨?
maxsize 是轮转触发条件,不是空间释放开关。它只决定“什么时候切”,不解决“切完服务跟不跟”。尤其在高频写入场景下,maxsize 100M 可能几分钟就触发一次,但若 postrotate 失败,你会看到 access.log.1、access.log.2……全都在持续变大。
- 验证方式:轮转后立刻
tail -f /var/log/nginx/access.log,如果没输出,说明新日志没被写入;再ls -l /var/log/nginx/access.log.*,看哪个文件时间最新、size 最大 - 常见陷阱:
daily和maxsize共存时,只要任一条件满足即轮转,但很多人只盯着时间,忽略 size 已早于 daily 触发 - 生产环境建议:至少配
maxsize 100M+postrotate,避免单文件突破 GB 级别后排查困难
真正卡点不在轮转动作本身,而在服务与 logrotate 之间的“契约”有没有被履行——信号是否送达、进程是否响应、fd 是否切换。这些环节任何一个断掉,都会让磁盘空间像漏了底的桶,越切越大。

















