如何在现代多核/多socket机器上扩展TCP侦听器

如何在现代多核/多socket机器上扩展TCP侦听器,c,unix,sockets,multithreading,c10k,C,Unix,Sockets,Multithreading,C10k,我有一个用C编写的守护进程,它需要同时处理20-150K TCP连接。它们是长期运行的连接,很少被拆掉。它们在任何给定时间的传输中都有非常少量的数据(甚至很少超过MTU,这是一个刺激/响应协议),但对它们的响应时间至关重要。我想知道当前的UNIX社区使用什么来获取大量套接字,并最大限度地减少它们的响应延迟。我见过围绕多路复用连接到fork工作池、线程(每个连接)、静态大小的线程池的设计。有什么建议吗?已经开发了几个系统来改进select(2)性能:,和。在所有这些系统中,您可以有一个工作线程池等

我有一个用C编写的守护进程,它需要同时处理20-150K TCP连接。它们是长期运行的连接,很少被拆掉。它们在任何给定时间的传输中都有非常少量的数据(甚至很少超过MTU,这是一个刺激/响应协议),但对它们的响应时间至关重要。我想知道当前的UNIX社区使用什么来获取大量套接字,并最大限度地减少它们的响应延迟。我见过围绕多路复用连接到fork工作池、线程(每个连接)、静态大小的线程池的设计。有什么建议吗?

已经开发了几个系统来改进select(2)性能:,和。在所有这些系统中,您可以有一个工作线程池等待任务;在使用其中一个文件句柄时,您不会被迫一次又一次地设置所有文件句柄。

您必须从头开始吗?您可以使用类似的东西。

最简单的建议是使用它,它使编写一个简单的非阻塞单线程服务器变得容易,符合您的要求

如果每个响应的处理都需要一些时间,或者如果它使用了一些阻塞API(类似于数据库中的任何东西),那么您将需要一些线程

  • 一个答案是工作线程,您可以在其中生成一组线程,每个线程侦听某个队列以工作。如果您愿意,它可以是单独的进程,而不是线程。主要区别在于告诉工人该做什么的沟通机制

  • 另一种方法是使用几个线程,并为每个线程提供150K连接的一部分。每个进程都有自己的进程循环,工作方式与单线程服务器类似,但侦听端口除外,它将由单线程处理。这有助于在内核之间分散负载,但如果使用阻塞资源,则会阻塞此特定线程处理的所有连接


libevent允许您在谨慎的情况下使用第二种方法;但还有另一种选择:。它不像libevent那样广为人知,但它特别支持多循环方案。

如果您有系统配置访问权限,请不要过度操作,并设置一些iptables/pf/etc,以便跨n个守护进程实例(进程)进行负载平衡连接,因为这将是现成的。取决于守护进程的阻塞性质,n应该与系统上的内核数相差多少倍或更高几倍。这种方法看起来很粗糙,但它可以处理损坏的守护进程,甚至在必要时重新启动它们。此外,迁移将是平滑的,因为您可以开始将新连接转移到另一组进程(例如,新版本或迁移到新框),而不是服务中断。除此之外,您还可以获得一些功能,如源关联,它可以显著帮助缓存和争用有问题的会话

如果您没有系统访问权限(或者ops不受打扰),您可以使用负载平衡器守护程序(有很多开源守护程序),而不是iptables/pf/etc,还可以使用n个服务守护程序,如上所述


这种方法还有助于分离端口的特权。如果外部服务需要在低端口上提供服务(如果性能非常关键,那么您真的需要使用多线程事件循环解决方案,即一个工作线程池来处理您的连接。不幸的是,在大多数Unix平台上都没有适用于此的抽象库(请注意,libevent和大多数事件循环库一样,都是单线程的),因此您必须自己完成这些脏活

在Linux上,这意味着使用带有工作线程池的边缘触发epoll(Windows将具有I/O完成端口,在多线程环境中也可以正常工作-我不确定是否有其他Unix)


顺便说一句,我已经做了一些工作,试图在Linux和Windows I/O完成端口上抽象边缘触发的epoll(这是正在进行的工作,但可能会提供一些想法)。

我认为javier的回答最有意义。如果你想测试这个理论,那么就看看javascript项目

Node基于Google的v8引擎,该引擎将javascript编译为机器代码,在某些任务中的速度与c一样快。它也基于libev,设计为完全无阻塞,这意味着您不必担心线程之间的上下文切换(一切都在单个事件循环中运行).在这方面,它与erlang非常相似

现在,用javascript编写高性能服务器对于node来说真的非常简单。您还可以用c编写自定义代码,并为node创建绑定以调用它来进行实际处理(查看node源代码了解如何做到这一点-文档目前有点粗略)。作为一个更丑陋的替代方案,您可以将自定义c代码构建为应用程序,并使用stdin/stdout与之通信

我自己测试过node,有超过150k的连接,完全没有问题(当然,如果所有这些连接都要同时进行通信,您将需要一些重要的硬件)。node.js中的TCP连接平均只使用2-3k内存,因此理论上每1GB RAM可以处理350-500k连接

注意-Node.js目前在windows上不受支持,但它只是处于开发的早期阶段,我想它会在某个阶段被移植


注意2-您必须确保从节点调用的代码不会阻塞

请重新格式化您的问题。单个水平滚动行没有多大帮助。@jldupont,语言对这有影响吗?这似乎是一个系统问题,而不是一些局域网问题