TOC

惊群与 accept_mutex

多个进程共享一个 bind socket 时,会发生这样的情况:一个连接进来,所有相关进程都从睡眠状态被唤醒。然后其中一个进程拿到这个连接,其他进程就继续 sleep。
这种现象就叫做惊群。好处就是如果来了大量连接的话,大家一起干活(可能可以算是正向的影响),坏处就是,如果只来了少量的连接,白白吵醒一众进程,消耗 CPU 资源。
这个好处像没有一样,资源的浪费确是实打实的。

注意,新版本 Nginx 上不需要互斥锁,默认没有惊群现象。

accept_mutex

Syntax: accept_mutex on | off;
Default: accept_mutex off;
Context: events

If accept_mutex is enabled, worker processes will accept new connections by turn. Otherwise, all worker processes will be notified about new connections, and if volume of new connections is low, some of the worker processes may just waste system resources.

There is no need to enable accept_mutex on systems that support the EPOLLEXCLUSIVE flag (1.11.3) or when using reuseport.

Prior to version 1.11.3, the default value was on.

如果 accept_mutex 启用,worker 进程会按顺序接受连接。否则,所有 worker 进程都会收到新连接通知,也就是惊群了。

1.11.3 之前,accept_mutex 默认是 on。为什么现在默认 off 了呢?
文档有写, 因为 1.11.3 之后,支持 EPOLLEXCLUSIVE 标记的平台,默认就不会发生惊群了,不需要 accept_mutex。

此外:如果使用了 TCP reuseport(需要 Linux 内核支持), 就不需要启用 accept_mutex。

如果 reuseport 参考: 2019/02/05, reuseport: 端口复用
PS: 2015/05 发布的 1.9.1 及之后版本,Nginx 引入了 reuseport 指令。

accept_mutex_delay

Syntax: accept_mutex_delay time;
Default: accept_mutex_delay 500ms;
Context: events

If accept_mutex is enabled, specifies the maximum time during which a worker process will try to restart accepting new connections if another worker process is currently accepting new connections.

如果 accept_mutex 启用,那么这个参数指定了 worker 进程申请 accept_mutex 锁失败之后的 sleep 时长。

也就是说如果出现竞争,没有抢到锁的进程就要睡眠一段时间,避免无效的反复申请锁。不过,感觉默认的这个 0.5 秒感觉有点长,50ms 应该就够了吧。

实现

参考:深入浅出 Linux 惊群:现象、原因和解决方案

附: 睡眠队列(等待队列)