Nginx Worker进程通过accept_mutex锁机制争抢新连接:抢锁成功者执行accept(),失败者立即处理已有连接,每轮事件循环重新竞争;启用reuseport后由内核哈希分发连接,自动禁用accept_mutex。

Nginx 的 Worker 进程通过“抢占式竞争 + 内核通知 + 用户态锁”协同处理任务,不是轮询也不是随机分配,而是在事件驱动框架下有策略地争抢新连接和共享资源。
Worker 进程如何争抢新连接
当客户端发起 TCP 连接请求,内核将该连接放入监听 socket 的 accept 队列后,会唤醒所有等待该 socket 的进程(即全部 Worker)。但 Nginx 默认启用 accept_mutex,要求每个 Worker 在调用 accept() 前必须先获取这把锁:
- 只有一个 Worker 能成功加锁并执行
accept(),拿到新连接后立即进入事件循环处理(读请求、转发、写响应) - 其余 Worker 抢锁失败,不阻塞,直接跳过 accept 阶段,转而处理已建立连接的读写事件(如长连接上的后续请求)
- 每次事件循环开始时都重新尝试抢锁,因此负载会随连接到达节奏自然分散,而非严格均匀
共享内存资源的并发访问控制
当多个 Worker 需要读写同一块共享内存(如限流计数器、SSL 会话缓存),Nginx 不依赖系统级互斥锁,而是使用轻量自旋锁 ngx_shmtx_t:
- 每个共享内存区(如
limit_req_zone定义的 zone)自带一把锁,但锁粒度更细:按哈希分桶,不同客户端哈希到不同 bucket,各自独立加锁 - 抢锁靠 CPU 原子指令(如
CMPXCHG),失败后短暂 pause 再重试,超 1024 次未果则让出 CPU - 锁变量与热点数据之间填充 padding,确保各自独占 cache line,避免伪共享拖慢性能
为什么不用线程或全局锁
Worker 进程彼此独立、不共享地址空间,天然规避了线程间同步开销和内存安全问题:
- 每个 Worker 处理完整请求生命周期(从 accept 到 close),无需跨进程传递上下文
- 共享状态仅通过预分配的共享内存 + 自旋锁访问,无系统调用、无上下文切换,延迟极低
- master 不参与请求处理,只做进程管理与配置加载,职责清晰、故障隔离强
现代优化:reuseport 替代 accept_mutex
Linux 3.9+ 内核支持 SO_REUSEPORT,Nginx 1.9.1+ 可启用:
- 在 listen 指令中添加
reuseport(如listen 80 reuseport;) - 内核直接将新连接哈希分发到某个 Worker 的监听 socket,完全绕过用户态抢锁逻辑
- 相比 accept_mutex,减少锁竞争、提升吞吐,是高并发场景下的推荐做法


















