设计服务器以获得性能的最佳方法是什么?

时间:2012-11-01 01:22:19

标签: c network-programming

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

  1. 你是否将套接字分成不同的线程并在每个线程上调用阻塞recv()?
  2. 您是否有一个位于select()循环中的线程,然后通知另一个线程处理各个端口?
  3. 您是否有一个处理select()和响应的线程?
  4. 你做2或3但是有端口集群而不是全部吗?
  5. 如果您使用上面指定的select,阻塞与非阻塞端口是否重要?
  6. setsockopt提高了性能:TCP_NODELAY,其他?
  7. 我意识到其中一些取决于用例。例如,如果存在大量小数据包,则关闭TCP_NODELAY的6会产生负面影响。 3听起来如果响应微不足道可能会更快。我还没有想到任何影响性能的其他问题。

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:2)

在我看来,最简单的代码是使用阻塞I / O的每个连接一个线程。使用您喜欢的线程模型也可以轻松编写。

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

我已经将这种方法用于适当数量(〜几十个)的连接,并在一对10GbE链路上以每秒超过一千兆字节的速度移动数据。 Linux内核的调度程序非常适合处理此范围内的线程计数。

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

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

答案 2 :(得分:0)

取决于。

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

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

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

您应该开始以模块化方式设计系统,以便您的工作人员不依赖于特定的实现(select / poll / epoll)。像setsockopt这样的东西可以在以后轻松更改,你根本不用担心它们。

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