正确做法是发送 kill -usr1 信号(等价 nginx -s reopen),nginx 主进程重新打开日志文件,工作进程继续写旧文件直至完成,新日志写入新文件,避免丢失。

关键在于不让 Nginx 写入中断——日志切割不是“搬走文件”,而是让 Nginx 主动换用新文件,旧文件句柄仍由工作进程持有直到写完最后一笔。只要信号触发和文件接管过程正确,就不会丢日志。
必须用 USR1 信号而非手动 mv
Linux 下进程写日志靠的是文件描述符(fd),不是文件名。直接 mv access.log access.log-20260905 不会立刻中断写入,但后续 Nginx 无法感知、也不会自动创建新文件,容易导致日志静默堆积到旧文件或丢失。
正确做法是发送 kill -USR1(等价于 nginx -s reopen):
- Nginx 主进程读取配置,以
access_log指令中声明的路径创建新文件(如/var/log/nginx/access.log)
logrotate 配置里要带 sharedscripts + postrotate
这是生产环境最稳的组合。避免多个日志文件(如 access.log、error.log、custom_api.log)被分别处理时重复发信号或漏发。
示例核心段:
/var/log/nginx/*.log {
daily
dateext
rotate 30
compress
delaycompress
missingok
notifempty
create 0644 nginx nginx
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
endscript
}
注意:sharedscripts 确保所有匹配文件轮转完只执行一次 postrotate;USR1 必须在所有文件重命名后发出,否则部分日志可能仍写向已重命名的旧文件。
避免常见误操作
以下行为会带来丢日志风险,需严格规避:
- 用
kill -HUP或nginx -s reload替代 USR1:会触发配置重载+连接平滑切换,但日志 reopen 是副作用,非保证行为,尤其在高并发下易出竞态 - 在
postrotate里调用nginx -t && nginx -s reload:多余且危险,reload 不等于 reopen - 未检查 pid 文件是否存在就强杀:应加
[ -f ... ]判断,防止信号发给错误进程 - 使用
copytruncate选项:它靠复制+清空原文件实现,复制间隙内新日志会丢失(尤其大流量时)
验证是否真不丢日志
上线前做两件事:
- 手动触发一次轮转:
logrotate -f /etc/logrotate.d/nginx,然后立刻压测(如ab -n 1000 -c 100 http://localhost/),检查旧文件末尾和新文件开头是否有连续请求 ID 或时间戳 - 查 Nginx error.log 是否出现
open() "/var/log/nginx/access.log" failed (2: No such file)类报错——说明 reopen 失败,新文件未成功创建











