开启 access_log 缓冲写入(buffer=64k flush=1s)不增加文件描述符,也不减少磁盘 I/O 总量,而是将高频小块随机写转为低频大块近似顺序刷盘,需用 iostat、iotop、strace 等工具验证 I/O 模式优化效果。

开启 access_log 的缓冲写入(buffer=64k flush=1s)本身不会增加文件描述符数量,也不会直接降低磁盘 I/O 总量,但它能显著改变 I/O 的行为模式——把高频、小块、随机的同步写,转为低频、大块、更接近顺序的批量刷盘。排查影响,关键不是看“有没有写”,而是看“怎么写”“写得有多集中”。
观察文件描述符是否异常增长
Nginx 对每个 access_log 文件在 worker 进程中只打开一个文件描述符(fd),且该 fd 在 reload 或日志轮转时才关闭重开。启用 buffer 不会新增 fd,也不会复用或共享 fd。
- 用
lsof -p $(pgrep nginx | head -1)查看主 worker 进程打开的 fd,确认/var/log/nginx/access.log是否只出现一次(类型为REG) - 若发现多个同名日志文件被同时打开(如
access.log和access.log.1),说明logrotate未配copytruncate或 Nginx 未执行kill -USR1重载,导致旧 fd 未释放——这与 buffer 无关,属运维配置问题 - 注意:使用
syslog方式(access_log syslog:...)会改用 socket fd(IPv4或unix类型),此时 fd 数量不变,但目标从文件变为网络端点
验证磁盘 I/O 模式是否真正优化
buffer + flush 的效果体现在 I/O 的频率、大小和等待时间上,而非总量减少。需用系统工具交叉验证:
- 运行
iostat -x 1,重点关注日志磁盘的await(平均每次 I/O 等待毫秒数)和%util(设备忙时百分比)。开启缓冲后,这两项应明显下降,尤其在高并发压测时 - 用
iotop -o -P定位实际触发写盘的进程,确认是nginxworker 还是rsyslogd;再用lsof -p [PID]查其写入目标是否为日志文件本身 - 通过
strace -p $(pgrep nginx) -e write,fsync,fdatasync -s 128观察系统调用:开启缓冲后,write()调用次数应大幅减少(因日志暂存内存),而fsync()或fdatasync()应按flush间隔规律出现(如每秒一次)
识别常见干扰项与误判点
很多看似“日志引起”的 I/O 抖动,其实和 access_log 缓冲无关:
-
error_log不支持 buffer/flush,若设为debug级别,会持续触发同步小写,iostat中看到的 I/O 很可能来自它,而非 access_log - 启用
client_body_in_file_only on或proxy_buffering off时,大请求体或响应体可能直写临时磁盘文件,这类 fd 在lsof中显示为/var/lib/nginx/body/xxx,易被误认为日志 fd - 若日志目录挂载在机械盘(HDD)且与其他业务共盘,即使开了 buffer,
await仍可能高——这不是配置无效,而是物理层瓶颈,需独立 SSD 分区 - 某些监控 agent(如 Prometheus node_exporter、journald)默认 tail 日志文件,会造成额外读 I/O 和文件句柄争抢,建议禁用或改用 socket/syslog 接入
配套检查项确保效果不打折
buffer 参数生效的前提是底层环境配合到位:
- 确认日志路径所在文件系统挂载时含
noatime(ext4)或nobarrier(XFS),避免每次写都更新访问时间元数据 - 检查
logrotate配置是否含copytruncate,否则rename()操作会阻塞 Nginx 写入,造成write()调用卡住,掩盖 buffer 效果 - 若使用
gzip压缩写入(access_log ... gzip),注意压缩本身消耗 CPU,且部分内核版本下压缩流无法被 buffer 完全覆盖,I/O 行为可能更复杂 - worker 进程数 × buffer 大小 = 实际内存占用,用
ps aux --sort=-%mem | head -5观察 nginx 内存是否异常升高,排除 buffer 设置过大导致的内存压力


















