Nginx高效分发静态资源的核心是非阻塞IO与零拷贝协同:通过epoll/kqueue事件驱动实现单进程万级并发,配合sendfile、tcp_nopush等配置绕过用户态拷贝,由内核直接将页缓存数据经DMA送至网卡,显著降低CPU和内存开销。

Nginx 之所以能高效分发静态资源,核心在于它把非阻塞 IO 和零拷贝(zero-copy)协同用到了实处——不是简单开启某个开关,而是靠事件驱动模型与内核能力的深度配合。
非阻塞 IO:让单进程扛住成千上万并发连接
Nginx 默认使用 epoll(Linux)或 kqueue(BSD)等高性能事件通知机制。每个 worker 进程不为每个连接开线程,也不阻塞等待数据就绪;而是注册监听 socket 的可读/可写事件,由内核主动通知“哪个连接准备好了”。这样,一个 worker 就能同时管理数万连接,CPU 不在等待 I/O 上空转。
关键点:
- worker_processes 设置建议匹配 CPU 核心数,避免上下文频繁切换
- worker_connections 需结合系统 ulimit -n 调整,确保足够承载并发文件描述符
- keepalive_timeout 要合理设置,复用 TCP 连接减少三次握手和慢启动开销
零拷贝:绕过用户态内存拷贝,直接送数据到网卡
传统文件发送流程是:磁盘 → 内核页缓存 → 用户态缓冲区 → 内核 socket 缓冲区 → 网卡。而 Nginx 在启用 sendfile 后,可跳过用户态拷贝环节,由内核直接从页缓存把数据推送至 socket,再经 DMA 引擎送到网卡——整个过程无 CPU 搬运,不占用户内存带宽。
启用方式(在 http 或 server 块中):
sendfile on;tcp_nopush on;
tcp_nodelay on;
说明:
- sendfile on 是零拷贝前提,必须开启
- tcp_nopush on 配合 sendfile,让内核在 TCP 缓冲区满或遇到 FIN 时才发包,减少小包数量
- tcp_nodelay on 对非 sendfile 场景(如代理响应)降低延迟,但对静态文件通常影响不大
真实生效条件:不只是配置,还要看文件大小和系统支持
零拷贝并非对所有请求都触发。Nginx 实际行为取决于:
- 文件是否在内核页缓存中(热文件更容易走 sendfile)
- 文件大小:极小文件(如
- 是否启用了 gzip、range 请求、add_header 等功能:这些会破坏 sendfile 流程,强制回退到用户态处理
- 操作系统版本:较老内核(如
进阶优化:配合 open_file_cache 和 directio 控制缓存粒度
对高频访问的小文件,open_file_cache 可缓存文件句柄和元信息,避免反复 open/stat 系统调用:
open_file_cache max=10000 inactive=60s;open_file_cache_valid 60s;
open_file_cache_min_uses 5;
对超大文件(如视频),若担心污染页缓存,可用 directio(需 Linux 2.6.22+)绕过内核缓存,配合 aio 使用:
aio threads;directio 4m;
注意:directio 与 sendfile 互斥,启用后零拷贝失效,需按业务权衡——热小文件重缓存,冷大文件重吞吐控制。











