nginx高效处理海量静态请求靠事件驱动、零拷贝与内存复用:单worker用epoll管理数万非阻塞连接,sendfile实现内核态零拷贝,连接池与slab分配器全程复用内存资源。

事件循环统一调度所有连接
每个 worker 进程只跑一个事件循环,用 epoll 监听成千上万个 socket 的读写状态。静态请求来了,不立刻读文件,而是先注册“可读事件”;等内核通知“这个 socket 有请求头到了”,才开始解析;再发现是 GET /logo.png,就转去查文件是否存在、是否有权限——全程不阻塞,空闲时就在 epoll_wait() 里待命。
关键点:
- socket 全部设为 non-blocking,recv() 或 send() 立即返回,没数据就 EAGAIN,马上切下一个就绪连接
- 一个 worker 可同时管理数万连接,哪怕 99% 在 keepalive 空闲状态,也不占 CPU
- 超时(如 read_timeout)、关闭连接、定时清理缓存,都由红黑树统一管理,无需额外线程轮询
静态文件走零拷贝路径
传统方式是:读文件 → 拷贝到用户态 buffer → 再 send() 到 socket,两次内存拷贝 + 两次系统调用。Nginx 默认启用 sendfile(),让内核直接从磁盘页缓存搬运数据到 socket 发送队列,绕过用户空间,省掉 2 次拷贝和上下文切换。
配合优化更进一步:
- 开启 tcp_nopush on:攒够 TCP 包再发,减少小包数量(适合大文件)
- 开启 tcp_nodelay on:对小文件或首字节敏感场景,禁用 Nagle 算法,降低延迟
- 设置 sendfile_max_chunk 512k:避免大文件阻塞事件循环,分块触发 sendfile
内存与连接全程复用
静态请求生命周期短、结构简单,Nginx 专门做了轻量化设计:
- 连接结构体(ngx_connection_t)在启动时预分配进连接池,用完不释放,下次直接重用
- HTTP 请求头解析用 slab 分配器,字段指针直接指向原始接收缓冲区,不字符串拷贝
- keepalive 复用同一 TCP 连接处理多个静态请求,省掉三次握手、TLS 握手(若启用了 HTTPS)
- 文件元信息(大小、mtime)缓存在内存中,配合 open_file_cache,避免反复 stat()
配置决定实际效率上限
再好的架构也得靠配置落地。几个关键指令直接影响静态服务能力:
- worker_connections 65535:单 worker 最大连接数,要结合 ulimit -n 设置
- use epoll:Linux 下显式指定,比默认 auto 更稳定
- multi_accept on:一次 accept 尽量收完已排队连接,应对突发流量
- open_file_cache max=10000 inactive=60s:缓存文件句柄和元数据,大幅减少 syscalls











