nginx的non-blocking io不直接解决大流量写入瓶颈,而是通过eagain循环续写保证不阻塞;真正影响性能的是缓冲策略(如access_log buffer=64k flush=5s)、落盘时机、内存控制与内核协同(如sendfile零拷贝)。

写操作本质是非阻塞循环,靠事件驱动续发
当 Nginx 向 socket 或磁盘写数据时,若内核发送缓冲区满或磁盘忙,send() 或 write() 立即返回 EAGAIN,不会卡住 worker 进程。Nginx 将该连接加入写事件队列,等 epoll 通知“可写”后再尝试续发——这是 Non-blocking 的核心价值:不阻塞、不浪费 CPU、不拖垮其他请求。
但注意:这仅保证“不卡”,不等于“写得快”。写慢仍会堆积 pending write,吃内存、拖延迟、甚至触发 OOM。
关键不在 IO 模式,而在缓冲怎么配
写入压力主要来自三类场景:access_log 落盘、proxy 响应缓存、client body 上传。每类都需针对性控缓存:
-
访问日志:用
access_log /path/log.log combined buffer=64k flush=5s;—— 内存攒批写,避免每请求一次小 IO -
代理响应:设紧约束,如
proxy_buffers 8 128k;(总 ≤1MB),proxy_busy_buffers_size 256k;,防后端分块响应导致缓冲无限膨胀 -
客户端上传:设
client_body_buffer_size 64k;,client_max_body_size 1g;,并指定高速盘做临时路径:client_body_temp_path /ssd/tmp 1 2;
规避真正写磁盘的路径,优先走零拷贝
对静态大文件(JS/CSS/图片),关闭 proxy buffering,启用内核级优化:
proxy_buffering off;sendfile on;tcp_nopush on;
这样响应体由内核直接从磁盘 DMA 到 socket 发送队列,绕过用户态内存拷贝和 Nginx 缓冲区,极大降低 CPU 和内存压力,也减少写入路径上的环节。
别让 error_log 成为写入黑洞
error_log 不支持 buffer/flush,debug 级日志直写磁盘,高频下极易打满 IO:
- 生产环境必须设为
error_log /var/log/nginx/error.log warn; - 如需调试细节,转 syslog:
error_log syslog:server=127.0.0.1:514,tag=nginx error;,由 rsyslog 异步落盘 - 禁用
debug级别,尤其在启用 SSL 或 proxy_pass 时,日志量可能指数级增长
排查隐藏写入源,别只盯 access_log
iowait 高 ≠ 日志惹的祸。用工具定位真实写入者:
-
iotop -o找出高 IO 的 nginx worker PID -
lsof -p $PID查看它正在写哪些文件(可能是 client_body_temp、proxy_temp、fastcgi_temp) - 检查是否误开
client_body_in_file_only on;,或proxy_max_temp_file_size设得过大











