multi_accept on通过让worker在单次事件循环中批量accept内核listen队列所有就绪连接,减少事件循环切换与accept系统调用次数,从而降低连接建立延迟;需满足epoll/kqueue、足够大的somaxconn、匹配的worker_connections及文件描述符限制。

开启 multi_accept on 能显著降低高连接速率下 worker 进程的 accept 延迟,核心在于让单次事件循环“清空”内核 listen 队列中所有已就绪连接,避免反复进出事件循环和频繁系统调用。
它怎么减少延迟?
当大量客户端同时完成三次握手(比如秒杀开始瞬间),内核 listen 队列会堆积多个已完成连接。默认 multi_accept off 时:
- worker 每次只调用一次
accept(),取走一个连接,然后立刻返回事件循环 - 哪怕队列里还有 99 个就绪连接,也要等下一轮 epoll_wait 返回后才继续处理
- 这造成明显的“处理空转”和延迟抖动,尤其在突发流量下
而 multi_accept on 后:
- worker 一旦被唤醒,就会持续调用
accept()直到返回EAGAIN或EWOULDBLOCK - 相当于一次性把当前队列里所有就绪连接全部捞出、分发给连接池或请求处理流程
- 减少了事件循环切换次数和上下文开销,连接建立延迟更平滑、更低
必须满足的生效条件
这个指令不是“一开就灵”,以下四点缺一不可:
- 事件驱动模型必须是
epoll(Linux)或kqueue(FreeBSD/macOS);select/poll下完全无效 - 内核参数
net.core.somaxconn要足够大(建议 ≥65535),否则队列满导致连接被丢,再快也无连接可取 - Nginx 的
listen指令最好显式加backlog=65535,与内核对齐 -
worker_connections和系统级文件描述符限制(ulimit -n或 systemdLimitNOFILE)要匹配,避免 accept 后无法分配资源
搭配 accept_mutex 和 reuseport 的取舍
延迟优化效果还取决于多 worker 协同方式:
- 若使用
accept_mutex on(旧版本默认),开启multi_accept可让抢到锁的 worker 一次多取,减少锁争用频率 - 若运行 Nginx ≥1.11.3 且未启用
reuseport,accept_mutex默认开启,此时multi_accept是关键增益点 - 若已启用
reuseport(需 Linux 3.9+、Nginx 1.9.1+),accept_mutex自动失效,每个 worker 可独立监听同一端口,此时multi_accept仍有效——每个 worker 都能批量取走自己分到的那部分就绪连接
验证是否真正起效
光改配置不够,得看实际行为:
- 用
strace -p $(pgrep nginx) -e trace=accept,accept4 -f在压测中抓取 worker 系统调用,观察是否连续多次accept成功返回(而非隔很久才一次) - 对比开启前后,用
wrk -c 10000 -t 4 http://host/dev/null测连接建立耗时(如--latency输出的 p95/p99),通常下降 20–50ms - 检查
netstat -s | grep "listen overflows"是否归零——说明内核队列不再溢出,accept 跟上了节奏










