Nginx access_log异步写入必须同时配置buffer和flush参数,缺一不可:仅设buffer=64k不加flush会导致宕机丢日志,仅设flush=1s不加buffer则被忽略;典型组合为buffer=64k flush=1s或buffer=32k flush=5s。
直接加 buffer 和 flush 参数就能让 access_log 异步写入,不需要改内核、不依赖外部进程,但必须两个参数一起用,缺一不可。
只设 buffer=64k 不加 flush,日志只在缓冲区满或 Nginx reload/quit 时才落盘,宕机就丢;只设 flush=1s 不加 buffer,Nginx 会忽略它——这两个参数是绑定生效的。
buffer=32k:每个 worker 进程为该日志分配最多 32KB 内存缓冲,日志先写内存,不立刻触发 write()
flush=1s:从上一次刷盘起计时,超 1 秒就强制把当前缓冲内容批量写出,防止滞留过久buffer=64k flush=1s(中高流量)、buffer=32k flush=5s(低峰或延迟容忍度高)access_log 指令会各自分配缓冲,总内存 = worker_processes × buffer_size × 日志条目数
error_log 指令根本不认 buffer 或 flush,所有输出默认同步直写磁盘。如果你开了 error_log /path/ warn; 还觉得 IO 高,问题大概率出在这儿。
warn 或 error
syslog:error_log syslog:server=127.0.0.1:514;,靠 libc 队列异步投递emerg)强制同步,这是硬编码行为,绕不开别只看配置 reload 成功,得确认系统调用行为变了。最直接的方式是跟踪 worker 进程的 write 和 fsync:
strace -p $(pgrep nginx) -e write,fsync -f 观察:开启后 write() 调用频次应大幅下降,fsync() 应基本按 flush 间隔出现/proc/$(pgrep nginx)/fd/ 下日志文件描述符类型,要是 pipe 或 socket,说明被重定向了,buffer/flush 不生效iostat -x 1 对比开启前后 await 和 %util,真实磁盘压力应明显降低buffer 大小和 flush 间隔不是越大胆越好——32KB 缓冲 + 5 秒刷新,在低 QPS 场景下可能让日志滞留近 5 秒才落地,安全审计或攻击溯源窗口就在这儿;而 worker 进程崩溃时,这部分内存日志永远丢失。真正稳住的关键,是把日志路径挂到独立 NVMe 分区,并加 noatime 挂载选项,否则内核页缓存再快,元数据更新也能拖慢整体节奏。