nginx worker 进程通过 accept_mutex 锁(仅在 epoll/kqueue、accept_mutex on、未启用 reuseport 且 backlog 空闲时生效)控制单进程 accept(),避免惊群;抢锁成功后快速处理就绪连接,结合 ngx_accept_disabled 动态让出实现负载均衡;现代推荐启用 reuseport 由内核直分连接,彻底规避用户态锁。

Nginx 的 Worker 进程通过内核事件机制与用户态锁协同工作,实现高效、低冲突的新连接接收。核心不是“谁先抢到谁处理”,而是由 accept_mutex 控制同一时刻仅一个 Worker 执行 accept(),避免所有进程同时唤醒争抢——即所谓“惊群效应”。
accept_mutex 锁的触发前提
这个锁不是始终生效的,它只在满足以下条件时才起作用:
- 使用 epoll 或 kqueue 作为事件驱动模型(select/poll 不启用该锁)
- 配置项
accept_mutex on;(Nginx 默认开启) - 未启用
reuseport(即 listen 指令没加reuseport参数) - 当前监听 socket 上没有积压的待处理连接(backlog 空闲)
Worker 抢锁与连接获取流程
每个 Worker 在事件循环中周期性尝试获取 accept_mutex(本质是共享内存中的原子标志位),抢到后立即进入连接接收阶段:
- 检查监听 socket 是否就绪(epoll 返回 EPOLLIN)
- 循环调用
accept4()(Linux)或accept(),直到返回EAGAIN或EWOULDBLOCK - 每次成功 accept 后,将新连接加入本 Worker 的连接池,交由事件模块异步处理
- 锁释放极快,仅覆盖 accept() 调用本身,不阻塞整个请求处理过程
负载均衡靠的是动态让出,不是轮询
Nginx 并不保证严格轮询分发连接,而是通过变量 ngx_accept_disabled 实现软性平衡:
- 该值 = 单个 Worker 当前总连接数 ÷ 8 − 空闲连接数
- 当值大于 0,Worker 主动放弃抢锁,把机会让给连接较少的兄弟进程
- 连接越多,让出概率越高,从而自然摊平各 Worker 的连接负载
现代推荐:用 reuseport 替代 accept_mutex
Linux 3.9+ 内核支持 SO_REUSEPORT,Nginx 1.9.1+ 可直接启用:
- 配置示例:
listen 80 reuseport; - 内核在底层将新连接直接分发到不同 Worker 的独立 socket 上
- 完全绕过用户态锁,无惊群、无竞争、无延迟抖动
- 启用后 accept_mutex 自动失效,无需手动关闭











