记录一下那天晚上的排查过程。CentOS 7.9 上 nginx 的 access.log 每小时切一次,审计要查某个时间段的请求,发现每次切分前后各有两三秒的记录完全找不到,logrotate 用的是 copytruncate,配置里没有 postrotate。
刚开始盯着「应用自己没 reopen,文件清空后仍往同一个 inode 追加」,折腾了半个多小时,排掉了。
把日志和配置对完,能解释这个现象的基本就这几处。copytruncate 先复制再清空,两步之间写进来的日志落在已复制的区间里,直接丢。也可能是日志涨到几个 G 时复制要好几秒,那个窗口被拉长,丢的就更多。
另外,压缩和删除放在同一轮,出错时旧文件已经没了,无从对照。
先确认当前用的是哪种切分方式
grep -E 'copytruncate|create|postrotate' /etc/logrotate.d/nginx
接着看新配置里 postrotate 有没有生效
logrotate -d /etc/logrotate.d/nginx 2>&1 | grep -A3 postrotate
手工验证 reopen 之后 inode 会不会变
ls -i /var/log/nginx/access.log; nginx -s reopen; ls -i /var/log/nginx/access.log
等前面都确认过,再抽样对比切分前后同一秒的请求
zgrep '10:00:0[0-3]' /var/log/nginx/access.log-* | tail -20
怎么算真的好了,看的是同一批现象。切分前后按秒抽查,请求记录连续没有缺口,access.log 的 inode 在切分后发生变化,旧文件里能看到完整的最后一秒内容。
这里还有个坑。create 模式要求应用支持 reopen,nginx 和 PHP-FPM 都认 USR1,自己写的程序得先实现信号处理;copytruncate 适合不能 reload 的场景,代价就是那几秒,取舍写进变更说明。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
