accept_mutex是Nginx多进程下避免惊群的有序抢答机制,通过共享内存CAS锁限制单worker执行accept(),配合multi_accept和ngx_accept_disabled实现自适应连接分发。

accept_mutex 是 Nginx 多进程模型中控制连接接入调度的核心机制,它不直接“解决”请求分配不均,而是通过互斥方式限制同一时刻仅一个 worker 进程执行 accept(),从而避免内核唤醒全部 worker 导致的 CPU 浪费和调度抖动。在现代 Linux 内核(≥2.6)和默认配置下,它已与 epoll ET + EPOLLONESHOT 协同工作,形成轻量、低开销的防惊群路径。
accept_mutex 的真实作用与适用边界
它不是负载均衡器,也不保证各 worker 连接数完全一致,而是一种“有序抢答”机制:
- 仅对 epoll、kqueue 等事件驱动模型生效;使用 select/poll 时该配置被忽略
- 在启用 reuseport(Linux 3.9+)时自动禁用——此时内核已在 socket 层完成连接分发,Nginx 不再需要用户态锁
- 默认开启(1.9.1+ 版本),无需手动配置;旧版本如 1.4.x 需显式写
accept_mutex on; - 锁本身基于共享内存 + 原子操作(CAS),无系统调用阻塞,worker 抢锁失败后立即进入事件处理循环,不休眠
配合 multi_accept 提升单次吞吐效率
当某个 worker 成功获取 accept_mutex 后,若只 accept 一个连接就释放锁,会频繁触发锁竞争。启用 multi_accept 可让该 worker 尽可能多地收尽当前就绪队列中的新连接:
- 配置为
multi_accept on;(默认 off) - 效果:一次抢锁成功后,循环调用 accept() 直到返回 EAGAIN,显著减少锁轮转次数
- 注意:需搭配非阻塞 listen socket(Nginx 默认满足),否则可能阻塞后续事件处理
动态调节:ngx_accept_disabled 实现软性负载倾斜
Nginx 内部用变量 ngx_accept_disabled 主动降低高负载 worker 的抢锁意愿,实现隐式连接数平衡:
- 计算公式:
ngx_accept_disabled = (max_connections / 8) - available_connections - 当该值 > 0,worker 自动跳过抢锁,把机会让给其他进程
- 无需人工干预,随每个 worker 当前连接水位自动生效,是轻量级的自适应机制
验证是否真正规避惊群现象
不依赖文档,用可观测手段确认实际行为:
- 压测时运行
pidstat -w -p $(pgrep nginx | head -n 3):若各 worker 的上下文切换(cswch/s)差异极大(如某 worker 持续高出 5 倍以上),说明 accept 调度仍不均,需检查是否误启 reuseport 或配置了 poll 模型 - 用
strace -p [worker_pid] -e trace=accept,futex观察:成功 worker 应有密集 accept 调用 + 少量 futex wait;其余 worker 几乎无 accept,仅有少量 futex 尝试 - 查看
ss -lnt输出中监听端口的 Recv-Q 是否持续为 0:非零值可能表明连接积压,间接反映 accept 处理能力瓶颈


















