核心思路是把“每次请求写一次盘”变成“攒一批再写”,同时剥离非核心日志路径,避免磁盘成为响应瓶颈;启用access_log buffer=64k flush=5s实现内存缓冲与定时刷盘,error_log调至warn级或转syslog,静态资源和健康检查接口关闭日志,并用logrotate定期轮转压缩。

核心思路是把“每次请求写一次盘”变成“攒一批再写”,同时剥离非核心日志路径,避免磁盘成为响应瓶颈。
启用 access_log 缓冲并调优参数
这是最直接有效的手段。Nginx 原生支持内存缓冲,无需额外模块:
- buffer=64k:日志先暂存在内存中,满 64KB 才批量落盘,大幅减少小 IO 次数
- flush=5s:即使缓冲未满,每 5 秒也强制刷一次,兼顾延迟与可靠性(断电最多丢 5 秒日志)
- 缓冲区大小建议设在 32k–128k 之间;过大增加宕机丢失风险,过小起不到聚合效果
分流或降级 error_log 写入压力
error_log 不支持 buffer 和 flush,高频率 debug 级日志极易拖垮磁盘:
- 生产环境将 error_log 级别设为 warn 或 error,避免记录海量 info/debug 日志
- 如需保留详细错误信息,可转向 syslog 输出:
error_log syslog:server=127.0.0.1:514,tag=nginx error;,由 rsyslog 异步处理 - 避免长期开启
debug级别,尤其在 proxy_pass 或 SSL 场景下,日志量呈指数增长
关闭非必要访问日志 + 合理轮转压缩
不是所有请求都值得记进主日志:
- 静态资源(
.js/.css/.png)和健康检查接口(如/healthz)可直接 access_log off - 使用 logrotate 定期切割压缩,配合
copytruncate避免重命名时的长连接阻塞 - 考虑启用 gzip 压缩写入(需编译含
--with-http_gzip_module):access_log /var/log/nginx/access.log.gz combined gzip flush=5s;
排查其他隐藏磁盘写入源
日志只是常见诱因,iowait 高不等于问题出在 access_log:
- 用 iotop -o 锁定高 IO 的 worker 进程 PID,再执行 lsof -p $PID 查看具体写哪些文件
- 确认是否启用了
client_body_in_file_only on,大 POST 请求体会直写磁盘 - 检查
proxy_max_temp_file_size是否被设为 0 却没配够内存缓冲(proxy_buffers),导致 502 后重试加剧 IO - fastcgi/uwsgi/scgi 协议有独立临时文件机制,与 proxy 相关参数无关,需单独审视











