非阻塞I/O是Nginx高并发的底层机制,由epoll/kqueue天然支持;buffer参数仅控制用户态数据暂存,需按业务类型精准配置以匹配非阻塞读写节奏。

非阻塞 I/O 是 Nginx 高并发能力的底层机制,它本身无需配置开启,而是由 epoll(Linux)或 kqueue(BSD)事件驱动天然支持。真正影响性能的,是缓冲区大小如何与非阻塞读写协同工作——既不让内存浪费,也不让 I/O 卡在等待或落盘上。
读懂 buffer 参数的真实作用
client_header_buffer_size、proxy_buffer_size 这类参数,不决定 I/O 是否阻塞,只控制数据在用户态如何暂存:
- client_header_buffer_size:默认 1k,用于收 HTTP 请求头;超长时回退到 large_client_header_buffers,否则直接返回 400
- client_body_buffer_size:默认 8k,请求体小于此值全内存处理;超过则写入 client_body_temp_path 临时文件
- proxy_buffer_size:仅缓存上游响应头(必须驻留内存),不能落盘;太小会触发 “upstream sent too big header” 错误
- proxy_buffers:缓存上游响应体,第一块大小等于 proxy_buffer_size,其余由 number size 定义
按业务类型精准设 buffer
盲目增大 buffer 不提升吞吐,反而增加延迟和内存压力:
- API 接口(JSON/REST):client_header_buffer_size 1k、client_body_buffer_size 8k 足够;若日志中频繁出现 400,说明 header 含大量 Cookie 或 JWT,可调 large_client_header_buffers 到 4 8k
- 文件上传服务:client_body_buffer_size 设为 32k–64k,同时确保 client_max_body_size 与实际业务匹配,避免小文件反复写 temp 目录
- 反向代理动态服务(如 FastCGI/gRPC):proxy_buffer_size 至少 12k,proxy_buffers 设为 8 16k(共 128k),兼顾响应头完整性和流式 body 缓冲
- 静态大文件分发:关闭 proxy buffering(proxy_buffering off),启用 sendfile on + tcp_nopush on,交由内核零拷贝传输
让缓冲策略适配非阻塞行为
非阻塞的核心是“有数据就读、没数据就跳过”,缓冲区必须配合这个节奏:
- 读阶段采用试探性读取:一次 recv() 只用当前可用缓冲空间,返回 EAGAIN 就暂停,不轮询也不阻塞
- 大请求体自动落盘:超过 client_body_buffer_size 或 client_max_body_size 时,直接写 client_body_temp_path,防内存暴涨
- 写阶段走零拷贝路径:sendfile on 后,静态文件由内核直送 socket;若需 gzip 或 sub_filter,则 sendfile 自动禁用,此时应评估压缩收益是否值得多一次内存拷贝
- 发送遇阻不空转:send() 返回 EAGAIN 时,Nginx 把连接挂进 write event 队列,等 epoll 通知“可写”再续发
避开常见陷阱
即使 I/O 非阻塞,配置不当仍会让性能打折:
- location 匹配用正则而非前缀(如 ^~ /static/),每次请求都做运行时解析,拖慢事件响应
- access_log 开启但无访问频率限制,高频小文件请求下 stat() 调用成为瓶颈;建议关闭或搭配 open_file_cache 使用
- worker_connections 设置过低,或 ulimit -n 未调高,导致 fd 耗尽,连接被拒绝,而非 I/O 阻塞
- 反向代理未启用 keepalive 连接复用,造成 TCP 握手频繁、TIME_WAIT 堆积,间接拉长非阻塞 worker 的等待链



















