最稳妥零丢日志的Nginx切割方式是SIGUSR1配合logrotate;该信号使主进程重开日志文件而不重启worker,确保服务不中断、日志不丢失,且需用sharedscripts避免多文件竞态。

直接用 SIGUSR1 信号配合 logrotate,是生产环境最稳妥、零丢日志的 Nginx 日志切割方式。关键不是“能不能切”,而是“切完 Nginx 还写不写旧文件”——只有发对信号、时机对、配置对,才能真正实现服务不中断、日志不丢失。
为什么必须用 SIGUSR1 而不是 kill -9 或 reload
Nginx 主进程收到 SIGUSR1 时,会执行“重新打开日志文件”动作:关闭当前正在写的 access.log 和 error.log 文件描述符,并按配置中 access_log 指令指定的路径,新建并写入同名新文件。这个过程不重启 worker 进程,不中断连接,也不丢请求日志。
而 nginx -s reload 会启动新 worker、逐步停旧 worker,虽也重开日志,但属于整站平滑升级行为,开销大;kill -9 更会导致日志写入中断甚至损坏。
- SIGUSR1 是专为日志 reopen 设计的信号,轻量且精准
- 它只影响日志文件句柄,不影响配置加载或进程生命周期
- 所有主流 Nginx 版本(包括源码编译版)均支持该信号
Logrotate 配置里必须包含 sharedscripts + postrotate
logrotate 默认对每个匹配文件单独执行脚本。如果 access.log 和 error.log 同时存在,不加控制就会发两次 USR1,可能引发竞态。正确做法是用 sharedscripts 保证整个配置块只运行一次 postrotate 脚本。
典型配置(存为 /etc/logrotate.d/nginx):
/var/log/nginx/access.log /var/log/nginx/error.log {
daily
missingok
rotate 30
compress
delaycompress
dateext
dateformat -%Y%m%d
create 0644 nginx nginx
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
endscript
}-
dateformat -%Y%m%d让归档文件名清晰可读,如access.log-20260509 -
create 0644 nginx nginx确保新日志文件权限和属主正确,避免因权限问题导致写入失败 -
delaycompress防止刚切完就压缩,给排查留出缓冲时间
手动验证与日常巡检要点
配置完成后别急着等 cron 触发,先手动跑一遍确认流程闭环:
- 执行
logrotate -vf /etc/logrotate.d/nginx(-v 显示过程,-f 强制执行) - 检查是否生成了带日期的归档文件,如
access.log-20260509 - 确认原
access.log文件大小是否归零或接近零(说明已 reopen) - 用
lsof -p $(cat /var/run/nginx.pid) | grep log查看主进程打开的日志文件路径是否已是新文件
日常要留意:/var/log/nginx/ 下是否有大量未压缩的旧日志堆积;nginx.pid 文件是否存在且内容有效;磁盘剩余空间是否持续下降——这些往往是信号未成功发送或脚本执行失败的迹象。
高流量场景建议按小时切,但需调整触发机制
QPS 超过 1000 时,单日志文件一小时就能达 GB 级。logrotate 原生只支持 daily/weekly/monthly,无法直接 hourly。可行解法是绕过 cron.daily,改用 crontab 每小时调用一次:
- 编辑
crontab -e,加入:0 * * * * /usr/sbin/logrotate -s /var/lib/logrotate/status /etc/logrotate.d/nginx - 注意加
-s指定状态文件路径,避免与 daily 任务冲突 - 配置中把
daily改成hourly并删掉dateext(否则每小时都加日期,命名重复),改用dateformat -%Y%m%d-%H
这种方式仍走 logrotate 流程,保留压缩、轮转数量等全部能力,只是调度更密,适合 CDN、API 网关等高频访问节点。


















