非阻塞I/O优化等待而非磁盘读写,需协同零拷贝(sendfile)、缓存(open_file_cache)和分层I/O(小文件用page cache+sendfile,大文件用directio+aio)提升并发性能。

非阻塞 I/O 本身不直接优化磁盘读写,它优化的是“等待”——让 Nginx 不因磁盘慢而卡住连接。真正提升海量并发下磁盘读写效率的,是把非阻塞模型和零拷贝、缓存、分层 I/O 等机制协同起来,让热数据尽量不碰磁盘,冷数据避开内核页缓存干扰。
用 sendfile 实现静态小文件零拷贝
高频小文件(CSS/JS/图标)若走常规 read() + write(),每次都要两次系统调用、两次内存拷贝。启用 sendfile 后,内核直接从 page cache 把数据送进 socket 缓冲区,跳过用户态,省掉全部拷贝开销。
- 必须配置:sendfile on;(默认通常已开)
- 搭配:tcp_nopush on;,攒满 TCP 报文段再发,减少小包数量
- 注意:gzip、sub_filter、etag 等模块会强制禁用 sendfile,纯静态服务建议关掉这些模块
靠 open_file_cache 拦住元数据系统调用
每秒几千次请求,若每次都 stat() 判断文件是否存在、open() 打开文件,光元数据操作就成瓶颈。open_file_cache 把文件句柄、大小、修改时间等缓存在内存里,大幅降低 syscalls 频次。
- 推荐配置:open_file_cache max=20000 inactive=30s;
- 补全关键项:open_file_cache_valid 60s;(定期校验有效性)、open_file_cache_min_uses 2;(至少被访问两次才进缓存)、open_file_cache_errors on;(缓存 failed 的 lookup,防反复试探)
- 静态路径务必用前缀匹配(如 location /static/ { ... }),避免正则解析消耗 CPU
按文件大小分层调度 I/O 方式
不能一刀切。小文件靠 page cache + sendfile 最高效;大文件若也走 page cache,反而挤占内存、引发换页抖动。合理分层才能兼顾吞吐与稳定性。
- 小文件(<4MB):保持默认,走内核页缓存 + sendfile
- 大文件(≥4MB):在 location 块中启用 directio 4m; 和 aio on;,绕过 page cache,异步直读磁盘
- SSD 存储挂载时加 noatime 参数,避免每次读都写访问时间戳
关掉干扰项,释放非阻塞模型的真实能力
非阻塞 I/O 能高效轮转上万连接的前提,是每个请求处理路径足够轻量。日志、压缩、动态重写这些功能,看似有用,但在高并发静态场景下,往往是性能断点。
- access_log off;(尤其 CDN 边缘或静态节点)
- 静态服务关闭:gzip off;、etag off;、expires off;(改用 Cache-Control 头控制)
- 避免在 Lua 或 proxy_pass 中做同步阻塞操作(如阻塞 DNS 查询),否则整个 worker 会被拖慢


















