Nginx通过accept_mutex实现互斥唤醒调度:仅一个worker抢锁成功后注册监听socket并处理accept,其余worker跳过,避免惊群;锁基于共享内存+原子操作,非内核阻塞。

accept_mutex 是 Nginx 在多 worker 进程场景下控制新连接接入节奏的核心机制,它不靠内核阻塞,而是让 worker 主动“轮值上岗”——每次只允许一个进程调用 accept(),其余进程专注处理已有连接。它不是万能锁,但却是稳定性和可预测性的基础保障,尤其在未启用 reuseport 的生产环境中不可或缺。
accept_mutex 的工作逻辑与默认行为
该机制本质是共享内存 + 原子操作的调度策略,而非传统互斥锁:
- Nginx 启动时在共享内存中创建一个轻量级互斥结构(
ngx_accept_mutex),所有 worker 进程均可原子读写 - 每个 worker 在进入
epoll_wait前尝试抢锁;抢到者将监听 socket 注册进自己的事件队列,获得 accept 权限 - 未抢到锁的 worker 不会休眠等待,而是继续处理已建立连接的读写事件,资源利用率高
- 抢锁成功者完成一轮 accept(直到返回
EAGAIN)后立即释放锁,其他 worker 可在下一轮竞争
自 Nginx 1.9.1 起默认开启(accept_mutex on),旧版本(如 1.4.x)需显式配置。它仅对 epoll 和 kqueue 有效,对 select/poll 无效——若误配事件模型,该机制自动失效。
配合 multi_accept 提升单次吞吐
单独开启 accept_mutex 只解决“谁来 accept”,而 multi_accept 决定“一次 accept 多少”:
-
multi_accept on;表示:抢到锁的 worker 在单次事件循环中尽可能多地调用accept(),收完当前就绪队列中的全部连接 - 这减少了锁轮转频率,降低上下文切换开销,特别适合突发短连接场景(如 HTTP API 请求洪峰)
- 建议与
accept_mutex on;成对使用,写在events块中
避免常见配置陷阱
一些看似“优化”的设置反而会削弱或绕过保护机制:
- 显式关闭
accept_mutex off;且未启用reuseport→ 直接退化为原始惊群模式 - 盲目设
worker_processes 64;(在 8 核机器上)→ 锁竞争加剧,pidstat -w可见 cswch/s 异常飙升 - 使用老旧第三方模块覆盖事件循环,干扰
ngx_trylock_accept_mutex()调用路径 - 容器环境未开放特权端口(如未设
net.ipv4.ip_unprivileged_port_start=0),导致reuseport绑定失败却无报错,静默回退到 mutex 模式
验证是否真正生效
不用压测,几个命令即可确认当前行为:
-
nginx -t && nginx -V 2>&1 | grep -i reuseport:检查是否支持且未被编译禁用 -
ss -tlnp | grep :80:若看到多个 PID 共同监听同一端口(且含reuseport字样),说明内核分流已启用,accept_mutex自动失效 -
pidstat -w -p $(pgrep nginx | head -n 3) 1:观察各 worker 的每秒上下文切换次数,平稳无突刺即表明锁调度健康 -
curl -s http://localhost/nginx_status | grep 'Accepts:':结合Accepted与Handled差值,可粗略判断连接分发是否趋近均衡



















