Linux 上还存在 Thundering Herd 问题吗?

问题描述 投票:0回答:5

许多 linux/unix 编程书籍和教程都谈到“Thundering Herd Problem”,当多个线程或分叉在 select() 调用上被阻塞以等待侦听套接字的可读性时,就会发生这种情况。当连接建立时,所有线程和分叉都会被唤醒,但只有一个“获胜”并成功调用“accept()”。与此同时,大量的CPU时间被浪费在无缘无故地唤醒所有线程/分叉上。

我注意到一个

项目为Linux内核中的这个问题提供了“修复”,但这是一个非常旧的补丁。

我认为有两种变体;一种是每个 fork 执行 select() 然后接受(),另一种是只执行 Accept()。

现代 unix/linux 内核在这两种情况下仍然存在雷群问题还是只有“select() then accept()”版本?

linux scalability
5个回答
16
投票
多年来,大多数 UNIX/Linux 内核都会序列化对accept(2) 的响应,换句话说,如果多个线程针对单个打开的文件描述符阻塞在accept(2) 上,则只会唤醒一个线程。

OTOH,正如您所描述的,许多(如果不是全部)内核在选择接受模式中仍然存在惊群问题。

我写了一个简单的脚本(

https://gist.github.com/kazuho/10436253)来验证问题的存在,发现问题存在于linux 2.6.32和Darwin 12.5.0上(操作系统 X 10.8.5).


12
投票
这是一个非常老的问题,而且大部分已经不存在了。 Linux 内核(过去几年)在处理和路由网络堆栈上的数据包的方式方面发生了许多变化,并且包括许多优化以确保低延迟和公平性(即最大限度地减少饥饿)。

也就是说,

select 系统仅通过其 API 就存在许多可扩展性问题。当您有大量文件描述符时,选择调用的成本非常高。这主要是因为必须构建、检查和维护传入和传出系统调用的 FD 集。

现在,执行异步 IO 的首选方法是使用

epoll。 API 更加简单,并且可以很好地跨各种类型的负载(许多连接、大量吞吐量等)进行扩展


2
投票
我最近看到测试了一个场景,其中多个线程在侦听的 unix 域套接字上进行轮询,然后接受连接。所有线程都使用 poll() 系统调用唤醒。

这是 Linux 内核的自定义构建,而不是发行版构建,因此也许有一个内核配置选项可以更改它,但我不知道那会是什么。

我们没有尝试 epoll。


2
投票
请参阅下面的链接,其中讨论了 epoll 的单独标志以避免此问题。

http://lwn.net/Articles/632590/


0
投票
它就在那里,而且是真实的。请参阅我们在 uwsgi 中看到的这个问题:

https://github.com/unbit/uwsgi/issues/2611

如果我在 uwsgi 中禁用 --thunder-lock 选项,这意味着 uwsgi 将不会使用系统的正确 api/锁定机制。在这种情况下,在我的峰值负载期间,我可以看到大量的上下文切换和大量的时间浪费。我的应用程序的响应时间始终如一。 (我正在谈论我的服务器上每分钟 1 个 Lac 请求)。

© www.soinside.com 2019 - 2024. All rights reserved.