防止定时任务并发切割导致系统过载,关键在于用 flock 文件锁实现互斥、错开 cron 时间、检查日志活跃度及优先采用 logrotate 的 sharedscripts 机制。

防止定时任务并发切割导致系统过载,关键不是“避开时间”,而是用锁机制和状态校验把并发控制住。Nginx 日志切割本身不耗 CPU,但多个实例同时执行 mv + nginx -s reopen + 清理操作,可能引发文件句柄竞争、重复压缩、误删或磁盘 I/O 突增——尤其在高流量站点凌晨整点触发时。
加文件锁,确保同一时刻只跑一个切割进程
用 flock 包裹整个脚本逻辑,是最轻量也最可靠的互斥手段:
- 在脚本开头加上:
flock -n /tmp/nginx-logrotate.lock -c '你的主逻辑' - 或更清晰的写法:脚本第一行后立即加
exec flock -n /tmp/nginx-logrotate.lock || exit 0,脚本末尾自动释放锁 - 锁文件路径建议用绝对路径(如
/tmp/nginx-logrotate.lock),避免因工作目录不同导致锁失效 -
-n表示非阻塞:若锁已被占用,当前脚本直接退出,不等待、不堆积
错开 cron 触发时间,降低整点冲击
即使有锁,也建议避免所有服务在同一秒触发。可对不同服务器或不同日志类型做微调:
- 主站日志:
0 0 * * * root /usr/local/bin/nginx-log-rotate.sh(凌晨 0 点整) - API 日志:
5 0 * * * root /usr/local/bin/nginx-log-rotate-api.sh(0 点 05 分) - 测试环境:统一延后 10–30 分钟,与生产环境隔离
- 若使用 systemd timer,可用
RandomizedDelaySec=60自动打散执行时间
切割前检查日志活跃度,空文件直接跳过
避免无意义的信号发送和文件操作,减少内核调度压力:
- 用
stat -c '%s' /var/log/nginx/access.log 2>/dev/null获取大小 - 若返回
0,说明当前无新日志写入,直接 exit 0,不执行 mv、reopen 或压缩 - 这对低峰期或刚重启的服务特别有用,能显著降低无效负载
用 logrotate 替代自定义脚本(推荐)
logrotate 原生支持 sharedscripts 和单次 postrotate,天然规避多文件并发问题:
- 配置中指定
/var/log/nginx/*.log { ... sharedscripts postrotate ... endscript } - 它会先收集所有匹配文件,再统一执行一次
postrotate,不会为每个 .log 单独发 USR1 - 配合
delaycompress和copytruncate(需 Nginx 支持),还能彻底绕过 reopen 竞争











