旧版 nginx(如 1.4.x–1.6.x、内核 2.6–3.8)需手动配置 accept_mutex on; 和 multi_accept on; 并使用 epoll 事件模型,才能有效避免“惊群”效应;否则默认关闭,且第三方模块、worker 数量不当或资源限制等均可能导致失效。

在旧版 Linux 内核(如 2.6–3.8)上,Nginx 默认不启用 accept_mutex,必须手动配置才能避免多 worker 进程被同时唤醒去争抢新连接——也就是“惊群”效应。它不是靠内核支持,而是靠 Nginx 自身的轻量级进程间锁协调接入顺序。
确认并开启 accept_mutex
旧版本 Nginx(如 1.4.x、1.6.x)默认是 accept_mutex off,必须显式打开:
- 在
events块中添加accept_mutex on; - 确保没写
use poll;或use select;—— 这两类事件模型会直接忽略该配置 - 推荐显式声明
use epoll;(Linux 下默认即 epoll,但显式写更稳妥) - 运行
nginx -t检查语法,再nginx -s reload生效(注意:旧版不支持动态重载此参数,需完整重启)
必须搭配 multi_accept 才有效
只开 accept_mutex 不够——它只决定“谁来 accept”,但若每次只收一个连接就释放锁,高并发下仍会频繁抢锁、加剧上下文切换:
- 在同一个
events块中加multi_accept on; - 这样抢到锁的 worker 会循环调用
accept()直到返回EAGAIN,一次性收完当前就绪队列里的全部连接 - 短连接洪峰下,各 worker 的上下文切换(
pidstat -w中的cswch/s)会明显更均衡
避开常见失效点
很多“配了却没用”的情况,其实是隐性冲突导致的:
- 第三方模块(尤其老旧 upstream 或 Lua 模块)可能覆盖
ngx_event_process_init(),跳过ngx_trylock_accept_mutex()调用 -
worker_processes设置远超 CPU 核心数(比如 32 核启 64 个 worker),锁轮转太密,反而放大抖动 -
worker_rlimit_nofile过低,导致accept()失败后反复重试,干扰正常调度逻辑 - 误配
accept_mutex_delay(旧版不支持)或写了accept_mutex off;,直接退回到原始惊群模式
验证是否真正起作用
别只看配置文件,要看运行时行为:
-
ss -tlnp | grep :80:应只看到一个 PID 在监听(说明未走reuseport,正依赖accept_mutex) -
strace -p $(pgrep nginx | head -1) -e trace=accept,futex -s 32 2>&1 | grep futex:持续输出futex(FUTEX_WAIT_PRIVATE)表示进程正在等锁,机制活跃 -
pidstat -w -p $(pgrep nginx | head -n 3):若某 worker 的cswch/s是其他 worker 的 3 倍以上,说明调度仍不均,大概率是multi_accept未开或事件模型错误










