nginx高并发日志丢失主因是缓冲溢出、轮转错位与采集脱节,需同步优化缓冲策略(如buffer=64k flush=3s)、统一轮转逻辑(dateext+sharedscripts+usr1)及采集韧性(filebeat close_inactive=30s等)。

Nginx 日志模块本身不叫“日志模块”,而是由 access_log 和 error_log 指令驱动的写入机制。所谓“缓冲区溢出丢日志”,本质是 日志写入链路中缓冲未及时落盘、轮转错位或采集脱节,不是传统内存溢出漏洞,但表现类似——高并发下部分请求没出现在 access.log 里。
要排查这个问题,得从三处下手:缓冲策略是否合理、日志轮转是否协同、采集端是否跟得上。单改一处效果有限。
缓冲配置不当导致内存滞留
Nginx 默认 buffer=8k,在 QPS 上千时极易积压。worker 进程异常退出(比如被 OOM killer 杀掉),缓冲区里还没 flush 的日志就永久丢失。
- 把
access_log改成显式带 buffer 和 flush:access_log /var/log/nginx/access.log main buffer=64k flush=3s;
- 确保
error_log也启用缓冲(虽默认不缓存,但高负载下建议统一):error_log /var/log/nginx/error.log warn buffer=32k flush=2s;
- 禁用 reload 触发日志 reopen:所有 reopen 必须由 logrotate 发送
USR1,而不是systemctl reload nginx或nginx -s reload,否则缓冲可能未清空就切换句柄。
轮转逻辑混乱引发覆盖或截断
Keepalived 主备节点各自跑 logrotate,容易生成同名时间戳文件,或权限错乱,导致部分日志被覆盖、截断甚至无法读取。
- 所有节点共用同一份 logrotate 配置,强制启用:
dateext dateformat -%Y%m%d-%H%M%S sharedscripts create 0600 nginx adm delaycompress
-
postrotate脚本中加校验:[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid) 2>/dev/null
- 避免
copytruncate:它会清空原文件,但 worker 进程仍往旧 inode 写,造成日志“消失”。
采集端(如 Filebeat)漏采旧文件或新文件
Filebeat 在日志轮转瞬间可能错过 rename 后的旧文件,或延迟发现新生成的 access.log,尤其当 close_inactive 太大时。
- 关键参数调优:
-
close_inactive: 30s(轮转后 30 秒内若无新内容就关闭 harvester) -
scan_frequency: 2s(更频繁扫描新文件) harvester_buffer_size: 65536- 禁用
max_bytes: 10485760(默认 10MB 易抖动),改用小块稳定读
-
- 启用持久化 registry,并确认其路径所在磁盘空间充足
- 传输链路必须走 TLS,避免网络丢包导致日志段丢失
不复杂但容易忽略











