nginx的异步非阻塞由多进程+单线程事件循环+epoll三层协同实现:worker初始化创建epoll实例并注册监听套接字,通过epoll_wait驱动事件循环,结合非阻塞i/o分段处理连接,单worker可高效并发处理成千上万请求。

Nginx 的异步处理不是靠单一线程或协程实现的,而是由多进程 + 单线程事件循环 + epoll 多路复用三层结构协同完成。它不为每个连接分配独立执行流,也不等待 I/O 完成,而是在少量 worker 进程内,把成千上万个连接的状态变化统一纳入一个高效调度体系。
worker 进程启动时就准备好事件循环
每个 worker 进程初始化时调用 ngx_event_process_init,完成三件事:
- 创建 epoll 实例(
epoll_create) - 注册监听套接字的读事件(
EPOLLIN) - 将所有待监控 socket 加入红黑树管理
此时事件循环尚未开始,只是建好“监听名单”。监听套接字被设为 non-blocking 模式,accept 调用不会卡住进程。
epoll_wait 驱动整个事件分发流程
核心函数 ngx_process_events_and_timers 每次循环执行以下动作:
- 先检查 accept 互斥锁,有权限则尝试接收新连接
- 调用
epoll_wait等待就绪事件,超时时间取自定时器红黑树最小值 - 若返回就绪事件,遍历
rdllist链表,分发给对应连接的读/写 handler - 若无就绪事件但定时器到期,则触发超时逻辑(如关闭空闲连接、重试 upstream)
关键点在于:epoll_wait 只在所有连接都无事可做且无定时器到期时才真正阻塞;其余时间它快速返回,让 Nginx 持续处理已就绪的 I/O。
非阻塞 I/O 在数据收发中落地为“分段续读/续写”
当某个连接触发 EPOLLIN 事件,Nginx 调用 recv:
- 若返回
EAGAIN或EWOULDBLOCK,说明暂时没数据——不等待,直接退出当前读流程 - 该连接的读事件保持注册状态,下次
epoll_wait再就绪时继续读 - 写操作同理:缓冲区满时写不全,就注册
EPOLLOUT,等可写再发剩余部分
这种机制使单个 worker 能交错处理多个连接的不同时期(如 A 正在传请求头、B 等待后端响应、C 正在发静态文件),没有一处因 I/O 停摆。
异步性体现在业务处理逻辑不依赖某次系统调用完成
需要明确的是:epoll 本身是同步接口,epoll_wait 会阻塞;但 Nginx 的“异步”是指对用户请求的处理逻辑不依赖某次 read/write 的完成。
- 接收请求体时,只读到部分数据就暂停,后续由事件回调驱动继续
-
ngx_connection_t是预分配、可复用的连接槽位,生命周期由连接池统一管理 - HTTP 请求通过
r->connection关联连接层与应用层,request pool 在请求结束时一次性释放,但连接可能复用(keepalive 场景)
本质上,Nginx 的异步是事件驱动下的协作式分时调度,不是操作系统级的异步 I/O(如 Linux io_uring),但足够支撑高并发低延迟的 Web 服务场景。











