7

对于处理大量套接字连接的程序(例如 Web 服务、p2p 系统等),似乎有几个选项可用。

  1. 生成一个单独的线程来处理每个套接字的 I/O。
  2. 使用select系统调用将 I/O 多路复用到单个线程中。
  3. 使用poll系统调用来多路复用 I/O(替换 select)。
  4. 使用epoll系统调用来避免必须通过用户/系统边界重复发送套接字 fd。
  5. 使用 poll API 生成多个 I/O 线程,每个线程多路复用一组相对较小的连接总数。
  6. 除了使用 epoll API 为每个独立的 I/O 线程创建单独的 epoll 对象之外,按照 #5。

在多核 CPU 上,我希望 #5 或 #6 具有最佳性能,但我没有任何硬数据支持这一点。搜索网络出现了这个页面,描述了作者在上面测试方法#2、#3 和#4 的经验。不幸的是,这个网页似乎有 7 年的历史,没有发现明显的最近更新。

所以我的问题是人们发现这些方法中的哪一种最有效和/或是否有另一种方法比上面列出的任何一种方法更好?对现实生活中的图表、白皮书和/或网络可用文章的引用将不胜感激。

4

4 回答 4

3

根据我运行大型 IRC 服务器的经验,我们曾经使用 select() 和 poll()(因为 epoll()/kqueue() 不可用)。在大约 700 个并发客户端时,服务器将使用 100% 的 CPU(irc 服务器不是多线程的)。然而,有趣的是,服务器仍然会表现良好。在大约 4,000 个客户端时,服务器将开始滞后。

这样做的原因是,在大约 700 个客户端时,当我们返回 select() 时,将有一个客户端可供处理。for() 循环扫描以找出它将占用大部分 CPU 的客户端。随着我们有更多的客户,我们会开始有越来越多的客户需要在每次调用 select() 时进行处理,因此我们会变得更有效率。

转向 epoll()/kqueue(),类似的规范机器可以轻松处理 10,000 个客户端,其中一些(当然更强大的机器,但按照今天的标准仍然被认为很小的机器)已经拥有 30,000 个客户端而不会破坏流汗。

我在 SIGIO 上看到的实验似乎表明它适用于延迟非常重要的应用程序,其中只有少数活动客户端做很少的个人工作。

我建议在几乎任何情况下都使用 epoll()/kqueue() 而不是 select()/poll()。我没有尝试在线程之间拆分客户端。老实说,我从来没有发现需要在前端客户端处理上进行更多优化工作来证明使用线程进行实验的服务。

于 2008-12-30T11:32:17.530 回答
2

在过去的两年里,我一直在研究这个特定的问题(对于 G-WAN 网络服务器,它带有许多基准和图表来揭示这一切)。

在 Linux 下工作得最好的模型是带有一个事件队列的 epoll(对于繁重的处理,还有多个工作线程)。

如果您的处理很少(处理延迟低),那么使用多个线程使用一个线程会更快。

这样做的原因是 epoll 不能在多核 CPU 上扩展(在同一个用户模式应用程序中使用多个并发 epoll 队列进行连接 I/O 只会降低服务器的速度)。

我没有认真看内核中的 epoll 代码(到目前为止我只关注用户模式),但我的猜测是内核中的 epoll 实现被锁削弱了。

这就是为什么使用多个线程很快就会碰壁的原因。

不用说,如果 Linux 想要保持其作为性能最好的内核之一的地位,那么这种糟糕的状态不应该持续下去。

于 2011-06-22T12:45:33.697 回答
2

From my experience, you'll have the best perf with #6.

I also recommend you look into libevent to deal with abstracting some of these details away. At the very least, you'll be able to see some of their benchmark benchmark results.

Also, about how many sockets are you talking about? Your approach probably doesn't matter too much until you start getting at least a few hundred sockets.

于 2008-09-30T20:46:47.330 回答
0

我广泛使用 epoll(),它表现良好。我通常有数千个套接字处于活动状态,并使用多达 131,072 个套接字进行测试。而 epoll() 总是可以处理它。

我使用多个线程,每个线程都轮询套接字的子集。这使代码复杂化,但充分利用了多核 CPU。

于 2008-09-29T16:44:35.937 回答