非阻塞io是nginx减少内核态上下文冗余调度的底层支点,通过o_nonblock使worker始终运行于用户态、epoll_wait批量通知就绪事件、单线程事件循环拆解为状态机,并协同sendfile零拷贝、tcp优化等机制,大幅压降挂起/唤醒及线程级切换开销。

非阻塞 IO 是 Nginx 减少内核态上下文冗余调度的底层支点,它不靠“减少调用次数”,而是彻底改变等待方式:让 worker 进程不再为单个连接被动挂起,转而由内核批量通知就绪事件,从而把调度粒度从“每个连接”提升到“每批事件”。
避免进程挂起与唤醒的成对切换
传统阻塞模型中,read() 或 accept() 在无数据时会触发进程睡眠——内核必须保存寄存器、切换调度队列、唤醒其他任务;等数据到达再恢复现场,又是一次完整上下文切换。高并发下,这形成大量成对的“挂起+唤醒”开销。Nginx 将所有 socket 设为 O_NONBLOCK,使系统调用立即返回 EAGAIN,worker 始终运行在用户态,不主动让出 CPU,也就跳过了绝大多数这类切换。
一次 epoll_wait 批量处理多个就绪事件
epoll_wait() 不是轮询,也不是为单个 fd 等待,而是在内核中一次性检查成千上万个 socket 的状态。只有至少一个 fd 就绪时才返回,并附带就绪列表。worker 拿到这个列表后,在用户态集中处理 accept、recv、send 等操作。这意味着: • 一次系统调用可驱动几十甚至上百次 I/O 行为 • 上下文切换频次取决于活跃事件数,而非总连接数 • 即使维持 10 万连接,只要其中仅数百个活跃,切换开销就只对应这数百个事件
单线程事件循环消除线程级调度干扰
每个 worker 是单线程事件循环,不创建新线程,不涉及线程抢占、栈切换或锁竞争: • 所有连接共享同一执行上下文,状态通过 ngx_connection_t 结构体维护 • 请求处理被拆解为小步状态机(如“读请求头→解析→转发→写响应”),每步执行完立刻转向下一个就绪事件 • 主进程只负责管理,worker 全权处理 I/O,职责隔离进一步压缩内核介入机会
协同内核特性压降隐式切换
非阻塞 IO 的收益需配合其他机制才能完全释放: • sendfile() 实现零拷贝:数据直接从 page cache 到 socket buffer,跳过用户态内存,省去 read()+write() 带来的两次系统调用和两次上下文切换 • tcp_nopush / TCP_CORK 合并小包,降低 send() 调用频次 • keepalive 复用连接,避免重复三次握手和四次挥手带来的协议栈调度负担 • worker_cpu_affinity 绑定核心,防止跨核缓存失效引发的额外调度抖动











