Nginx Worker Process 通过调用内核 sendfile() 实现零拷贝,需同时配置 sendfile on、tcp_nopush on、tcp_nodelay off,并仅对本地真实静态文件生效;代理、gzip、响应改写等会使其实质退化为 read/write 模式。

Nginx 的 Worker Process 本身不直接“实现”零拷贝,而是通过调用 Linux 内核提供的 sendfile() 系统调用,在内核态完成文件到网络套接字的高效传输——这才是零拷贝的核心机制。Worker Process 的角色是触发并协调这一过程,而非在用户空间搬运数据。
关键在于:零拷贝不是 Worker 进程自己写的代码逻辑,而是它在处理静态文件请求时,主动启用内核能力的结果。
零拷贝依赖的配置项必须开启
Worker Process 要走零拷贝路径,需满足以下基础配置(缺一不可):
-
sendfile on;
启用内核sendfile()系统调用,跳过用户空间缓冲区。 -
tcp_nopush on;
配合sendfile使用,让内核把数据攒成完整的 TCP 包再发,减少小包数量。 - 文件必须是本地磁盘上的真实文件(如
.html,.js,.png),且未被代理、重写或动态生成。
⚠️ 注意:如果 Nginx 作为反向代理(
proxy_pass)、启用了sub_filter、gzip或add_header等修改响应体的操作,sendfile会自动失效——因为数据已不再是原始文件,无法直接由内核从磁盘映射发送。
Worker Process 在其中做什么
当一个 HTTP GET 请求命中静态资源时,Worker Process 执行如下关键动作:
- 解析 URI,定位到对应磁盘文件路径;
- 检查该文件是否可直接
sendfile(权限、大小、是否被缓存等); - 若满足条件,调用
sendfile(fd_in, fd_out, offset, count)——
其中fd_in是打开的文件描述符,fd_out是客户端 socket 描述符; - 不再调用
read()+write(),避免四次拷贝和两次上下文切换; - 整个传输过程由 DMA 和内核完成,CPU 几乎不参与数据搬运。
你可以用 strace -p <worker_pid> -e sendfile 观察到该系统调用被频繁触发。
影响零拷贝生效的实际限制
即使配置正确,也可能因以下原因退回到传统拷贝模式:
- 文件太小(< 1KB):某些内核版本对极小文件会绕过
sendfile,直接用write(); - 启用了
directio(如directio 8m;):二者互斥,directio优先级更高; - 启用了
aio但未配aio threads或内核不支持异步 sendfile; - 文件系统不支持
mmap(如某些网络文件系统 NFS v3); - 客户端连接使用了 TLS:
sendfile在 SSL/TLS 场景下不可用(加密必须在用户空间做)。
验证是否真走了零拷贝
最直接方式是观察系统调用行为:
# 找到一个 worker 进程 PID(比如 4455) strace -p 4455 -e trace=sendfile,read,write 2>&1 | grep sendfile
如果看到大量 sendfile( 输出,且几乎无 read( / write(,说明零拷贝已生效。
也可配合 ss -i 查看 TCP 连接的 sndbuf 和 rcvbuf 使用情况——零拷贝下 socket 发送缓冲区占用更平稳,突发吞吐更稳定。
不复杂但容易忽略


















