Nginx事件循环只调度网络I/O,不处理磁盘I/O;磁盘读取默认同步阻塞,需靠sendfile、Linux AIO或后端卸载实现非阻塞,二者通过操作系统原生机制分离调度,无统一EventLoop。

Nginx 的异步事件驱动模型本身不直接处理非阻塞磁盘 I/O,它对磁盘文件的读取默认是同步阻塞的;所谓“异步”仅体现在网络 I/O 上。要实现非阻塞磁盘访问,需依赖外部机制配合,而非靠其事件循环统一调度。
Nginx 的事件循环只管网络,不管磁盘
Nginx 每个 worker 进程运行一个独立的事件循环(基于 epoll/kqueue),但它只监听和调度 socket 相关事件(如 accept、read、write)。当请求需要读取静态文件(比如 /index.html),Nginx 默认调用 read() 系统调用——这是同步阻塞行为:worker 会停在此处,直到内核完成磁盘读取并把数据拷贝到用户空间缓冲区。这会拖慢整个事件循环,降低并发能力。
实现非阻塞磁盘 I/O 的三种可行路径
-
sendfile 系统调用(零拷贝,推荐优先使用)
- 不经过用户空间,直接由内核将文件内容从磁盘页缓存复制到 socket 发送缓冲区
- 无需
read()+write(),避免两次内存拷贝和用户态阻塞 - 配置示例:
sendfile on; tcp_nopush on; - 限制:仅适用于文件直接发送给客户端的场景(如静态资源),不支持内容修改或动态拼接
-
Linux AIO(异步 I/O 接口)
- 使用
io_submit()/io_getevents()绕过页缓存,发起 DMA 级别读取 - 要求:Linux 内核 ≥ 2.6.22、文件系统支持(如 ext4/xfs)、配置启用
aio on;和directio - 注意:AIO 在 Nginx 中仅对
sendfile off且directio触发的场景生效,且不与所有模块兼容(例如不支持 SSL 场景下的 AIO 文件读取)
- 使用
-
交由后端服务处理磁盘 I/O
- 将文件读取逻辑卸载到上游应用(如 FastCGI、uWSGI、gRPC 服务)
- Nginx 仅作反向代理,通过非阻塞 socket 与后端通信,自身不触碰磁盘
- 优势:解耦清晰,可利用后端语言的异步生态(如 Python asyncio、Node.js stream)
为什么没有统一 EventLoop 协调磁盘与网络?
Nginx 设计哲学是“轻量、确定性、贴近系统”。它不模拟 Node.js 或 Rust Tokio 那样的通用用户态事件循环,而是信任并封装操作系统原生能力:
- 网络就绪靠
epoll_wait()主动通知 - 磁盘就绪若用 AIO,则靠
io_getevents()轮询完成队列(仍是内核级异步) - 二者调度逻辑分离,无共享状态机,避免跨域复杂性
不复杂但容易忽略



















