许多 linux/unix 编程书籍和教程都谈到“Thundering Herd Problem”,当多个线程或分叉在 select() 调用上被阻塞以等待侦听套接字的可读性时,就会发生这种情况。当连接建立时,所有线程和分叉都会被唤醒,但只有一个“获胜”并成功调用“accept()”。与此同时,大量的CPU时间被浪费在无缘无故地唤醒所有线程/分叉上。
我注意到一个项目为Linux内核中的这个问题提供了“修复”,但这是一个非常旧的补丁。
我认为有两种变体;一种是每个 fork 执行 select() 然后接受(),另一种是只执行 Accept()。现代 unix/linux 内核在这两种情况下仍然存在雷群问题还是只有“select() then accept()”版本?
OTOH,正如您所描述的,许多(如果不是全部)内核在选择接受模式中仍然存在惊群问题。
我写了一个简单的脚本(
https://gist.github.com/kazuho/10436253)来验证问题的存在,发现问题存在于linux 2.6.32和Darwin 12.5.0上(操作系统 X 10.8.5).
也就是说,
select 系统仅通过其 API 就存在许多可扩展性问题。当您有大量文件描述符时,选择调用的成本非常高。这主要是因为必须构建、检查和维护传入和传出系统调用的 FD 集。
现在,执行异步 IO 的首选方法是使用epoll。 API 更加简单,并且可以很好地跨各种类型的负载(许多连接、大量吞吐量等)进行扩展
这是 Linux 内核的自定义构建,而不是发行版构建,因此也许有一个内核配置选项可以更改它,但我不知道那会是什么。
我们没有尝试 epoll。