1

我正在尝试创建一个我希望有高性能需求的服务器。这个问题涉及服务器核心。哪些编程思想最能支持快速性能?

  1. 您是否将套接字拆分为不同的线程并在每个线程上调用阻塞 recv()?
  2. 您是否有一个线程位于 select() 循环中,然后通知另一个线程处理各个端口?
  3. 你有一个线程来处理 select() 和响应吗?
  4. 你是做 2 个还是 3 个,但使用的是端口集群而不是所有端口?
  5. 如果您使用上面指定的选择,使用阻塞与非阻塞端口是否重要?
  6. 什么setsockopt 提高性能:TCP_NODELAY,其他?

我意识到其中一些取决于用例。例如,如果有很多小数据包,关闭 TCP_NODELAY 的 6 会产生负面影响。如果响应微不足道,3 听起来可能会更快。我还没有想到会影响性能的任何其他问题也将不胜感激。

4

3 回答 3

3

我将从单线程方法开始:使用非阻塞 I/O 和快速轮询机制,如 Linux 上的边缘触发 epoll。(其他平台也有类似的技术。)围绕轮询循环的所有内容可以极大地简化程序设计,所以我肯定也会在其中添加 signalfds、timerfds 和 eventfds。然后一切都由一个中央循环处理。

如果并且当您需要使用多线程时,这可能就像同时运行多次主循环一样简单。如果您将事件设置为“一次性”,它们将在轮询中被禁用,直到重新启动,因此处理事件的线程可以安全地假设是唯一这样做的线程(并在最后重新武装事件)。您只需要同步程序不同部分之间的通信,或共享数据访问,但轮询器已经处理了很多同步。

于 2012-11-01T01:31:36.350 回答
2

在我看来,最简单的编码是每个连接使用阻塞 I/O 一个线程。使用您最喜欢的线程模型也很容易进行可移植的编写。

多路复用非阻塞 I/O 的问题是维护每个连接的状态。例如,我想写 1024 个字节,但write只消耗了 900 个……所以现在必须记住 124 个字节,以便以后再写。这只是原始“发送缓冲区”级别的状态;考虑整个协议的状态,它会很快变得复杂。当然,没有什么是不可能的,但是假设连接不需要相​​互交互(很多),只使用阻塞调用要简单得多。

我已将这种方法用于少量(约数十个)连接,并在一对 10GbE 链路上以每秒超过 1 GB 的速度移动数据。Linux 内核的调度程序非常擅长处理此范围内的线程数。

对于为成千上万的客户提供服务的 Web 服务器类型的东西......好吧,我没有亲自尝试过。我读过多路复用技术(epoll等)在这种情况下更快。正如其他人所说,这取决于您的应用程序。

但是,如果您的应用程序和我的一样(连接数量适中,它们之间的交互有限),那么“每个连接一个线程”的方法会胜出,IMO。

于 2012-11-01T02:19:03.800 回答
0

这取决于。

这类问题很难回答;这将是项目本身的角色之一。您将需要测量服务器在将要面临的工作负载下的性能,然后查看哪些选项最适合您的用例。

例如,设置 TCP_NODELAY 将减少请求的延迟,但该选项的存在是有原因的;您将通过设置 TCP_NODELAY 来降低吞吐量。

以下网站包含一些您应该查看的信息:http: //www.kegel.com/c10k.html。其中一些现在有点老了(几年前),但它包含了您应该考虑使用的技术列表:epoll、异步 I/O。

您应该着手以模块化方式设计您的系统,这样您的工作人员就不会被绑定到特定的实现(select/poll/epoll)。像 setsockopt 这样的东西以后可以很容易地改变,你根本不用担心它们。

先让它工作——然后让它“快”;无论您所说的“快速”是什么意思。如果你想要一些可扩展的东西,那么请注意你的算法的大 O(O(n)、O(n^2) ... 等)。

于 2012-11-01T01:43:30.160 回答