惊群
文章目录
惊群(thundering herd)
多个进程/线程同时阻塞等同一个事件时,事件发生后,唤醒所有的进程,但最终只可能有一个进程/线程对该事件进行处理,其他在失败后重新休眠,这种性能浪费就是惊群
accept 惊群
主进程创建socket, bind, listen后,fork出多个子进程都循环处理(accept)这个socket
每个进程都阻塞在accpet上,当一个新的连接到来时,所有的进程都会被唤醒,但其中只有一个进程会accept成功,其余皆失败,重新休眠。这就是accept惊群
fork出多个进程是为了利用多核CPU
内核早解决这问题了
多个进程/线程都阻塞在对同一个 socket 的 accept 调用上时,新连接到来,内核只唤醒一个进程,其他进程保持休眠,压根就不会被唤醒
epoll惊群
accept 已无惊群问题,但 epoll 还有
即,如果多个进程/线程阻塞在监听同一个 listening socket fd 的 epoll_wait 上,当有一个新的连接到来时,所有的进程都会被唤醒。
考虑如下场景:
主进程创建 socket, bind, listen 后,将该 socket 加入到 epoll 中,然后 fork 出多个子进程,每个进程都阻塞在 epoll_wait 上,如果有事件到来,则判断该事件是否是该 socket 上的事件,如果是,说明有新的连接到来了,则进行 accept 操作。为了简化处理,忽略后续的读写以及对 accept 返回的新的套接字的处理,直接断开连接。
那么,当新的连接到来时,是否每个阻塞在 epoll_wait 上的进程都会被唤醒呢?
很多博客中提到,测试表明虽然 epoll_wait 不会像 accept 那样只唤醒一个进程/线程,但也不会把所有的进程/线程都唤醒。例如这篇文章:关于多进程 epoll 与 “惊群”问题。
为什么内核不处理 epoll 惊群
accept 应该只能被一个进程调用成功,内核很清楚这一点
但 epoll 监听的fd,除可能被 accept 调用外,还有可能是其他网络 IO 事件的
其他 IO 事件是否只能由一个进程处理(如一个文件会由多个进程来读写),得用户决定,内核不能强制
所以,对 epoll 的惊群,内核则不予处理