Nginx 中 sendfile 与 mmap 互斥:启用 sendfile 时 mmap 不生效,因其走内核零拷贝路径(DMA 直传 PageCache 到网卡),无需用户态参与;关闭 sendfile 后,配合 aio threads 或 directio 等配置,才可能间接利用 mmap 优化读取。

Nginx 中 sendfile 与 mmap 并不协同工作,而是互斥关系——启用 sendfile 时,mmap 不生效;反之,关闭 sendfile 后,Nginx 才可能进入依赖 mmap 的路径。
sendfile 是默认优先路径
Nginx 静态文件服务默认开启 sendfile on;。此时内核直接通过 sendfile() 系统调用,将 PageCache 中的文件数据经 DMA 直送网卡,全程不经过用户空间,也不触发 mmap 映射。这是真正的零拷贝路径,系统调用少、上下文切换少、CPU 开销极低。
- 适用于纯转发场景:如 HTML、JS、CSS、图片等静态资源分发
- 不可修改内容:数据从磁盘到网络全程只读,无法在传输中做动态处理(如替换变量、加水印)
- 无需额外配置:只要文件句柄可读、socket 支持,即自动启用
mmap 需要主动“让路”才能启用
mmap 在 Nginx 中没有显式开关,但可通过关闭 sendfile,并配合其他 I/O 模式,间接促使 Nginx 使用基于内存映射的行为:
-
sendfile off;:强制退出零拷贝路径 -
aio threads;或directio 4k;:启用异步 I/O 或直接 I/O,使大文件读取更倾向走页映射+用户态缓冲路径 -
open_file_cache配合高命中率:减少反复open()/mmap()开销,提升映射复用效率
注意:这并非 Nginx 主动调用 mmap(),而是内核在处理文件读取时,对已缓存页自动采用映射方式访问,从而降低拷贝成本。
实际选型看需求,不是看技术名
是否需要“改数据”,是决定路径的关键:
- 只读分发(90% 静态资源)→ 保持 sendfile on,性能最优
- 需动态处理(如按请求拼接片段、注入 header、加密/解密)→ 关 sendfile,用常规 read/write + 缓冲,必要时由应用层控制 mmap 行为
- 超大文件随机访问(如视频切片、数据库导出)→ 可考虑自定义模块或上游服务用 mmap 预加载,Nginx 仅作代理
别混淆“零拷贝”层级
sendfile 和 mmap 都被称为“零拷贝”,但含义不同:
- sendfile:内核态直达,无 CPU 拷贝,无用户态参与,真正零拷贝
- mmap:省去一次内核→用户拷贝,但 write 仍需 CPU 将映射页复制到 socket buffer,属于“单次拷贝”优化
- 高并发下,sendfile 的上下文切换更少(1 次系统调用),mmap+write 至少 2 次,易成瓶颈
所以不是谁“更好”,而是谁更适合当前任务——Nginx 的设计哲学正是让简单事极简,复杂事交由上游或扩展模块完成。


















