当前位置: 首页 > 知识库问答 >
问题:

我们是否应该使用多个接受器套接字来接受大量的连接?

通安宁
2023-03-14

众所周知,SO_REUSEPORT允许多个套接字侦听相同的IP地址和端口组合,它将每秒的请求增加2-3倍,并减少延迟(~30%)和延迟的标准偏差(8倍):https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/

NGINX release 1.9.1引入了一个新特性,支持使用SO_REUSEPORT套接字选项,该选项在许多操作系统的较新版本中可用,包括DragonFly BSD和Linux(内核版本3.9和更高版本)。此套接字选项允许多个套接字侦听同一IP地址和端口组合。然后内核对跨套接字的传入连接进行负载平衡。...

如图所示,reuseport将每秒请求数增加2到3倍,同时降低了延迟和延迟的标准差。

so_reuseport在大多数现代操作系统上可用:Linux(自2013年4月29日起内核>=3.9)、Free/Open/NetBSD、MacOS、IOS/WatchOS/TVOS、IBM AIX 7.2、Oracle Solaris 11.1、Windows(在BSD中,只有so_reuseport表现为两个标志一起的so_reuseport+so_reuseaddr);也可能在Android上:https://stackoverflow.com/A/14388707/1558037

Linux>=3.9

也知道,为了避免自旋锁的锁和实现高性能,不应该有读取超过1个线程的套接字。即。每个线程都应该处理自己的套接字进行读/写。

  • accept()是同一套接字描述符的线程安全函数,因此应该由锁保护-因此锁争用会降低性能:http://unix.derkeiler.com/newsgroups/comp.unix.programmer/2007-06/msg00246.html

POSIX.1-2001/SUSV3需要accept()、bind()、connect()、listen()、socket()、send()、recv()等作为线程安全函数。可能标准中关于它们与线程的交互有一些不明确之处,但其意图是它们在多线程程序中的行为受标准的约束。

    null
  • 有关应用程序尝试从套接字读取数据时的spin-lock的更多详细信息-“Linux UDP套接字并发性能分析”:http://www.jcc2014.ucm.cl/jornadas/workshop/wsdp%202014/wsdp-4.pdf

V.K ERNEL隔离

....

我们有2台Xeon 32 HT-Cores服务器,共64个HT-Cores,两个10 Gbit以太网卡和Linux(内核3.9)。

我们使用RFS和XPS-即,对于同一个连接,TCP/IP-堆栈处理(内核空间)与应用程序线程(用户空间)在同一个CPU核上。

至少有3种方法可以在多个线程上接受对其进行处理的连接:

    null

共有1个答案

蓬弘
2023-03-14

在生产中必须处理这样的情况,下面有一个解决这个问题的好方法:

首先,设置一个单线程来处理所有传入的连接。修改关联映射,使这个线程有一个专用的核心,您的应用程序(甚至您的整个系统)中的其他线程都不会尝试访问。您还可以修改引导脚本,使某些内核永远不会自动分配给某个执行单元,除非明确请求特定的内核(即isolcpus内核引导参数)。

将该核心标记为未使用,然后通过cpuset在“Listen to Socket”线程的代码中显式请求它。

  • 接受()传入连接。
  • 尽可能快地将这些连接文件描述符传递给Writer优先级队列结构。
  • 尽快返回其accept()状态。

这将允许您尽可能快地委派传入连接。工作线程可以在项目到达时从共享队列中抓取项目。还有一个高优先级的第二个线程也是值得的,它从这个队列中抓取数据,并将其移动到辅助队列中,从而使“侦听套接字”线程不必花费额外的周期来委托客户端FDS。

这还将防止“侦听套接字”线程和辅助线程必须同时访问同一个队列,从而避免出现最坏的情况,例如当“侦听套接字”线程希望在队列中丢弃数据时,慢速的辅助线程锁定队列。即。

Incoming client connections

 ||
 || Listener thread - accept() connection.
 \/

Listener/Helper queue

 ||
 || Helper thread
 \/

Shared Worker queue

 ||
 || Worker thread #n
 \/

Worker-specific memory space. read() from client.

乱七八糟的。线程将不得不以某种方式轮流发出accept()调用,这样做没有任何好处。您还将有一些附加的排序逻辑来处理哪个线程的“turn”是向上的。

使用多个接受器套接字侦听相同的IP:端口,每个线程中有一个单独的接受器套接字,然后由接收连接的线程处理它(recv/send)

不是最便携的选择。我会避免的。此外,您可能需要使服务器进程使用多进程(即fork()),而不是多线程,这取决于操作系统、内核版本等。

 类似资料:
  • 问题内容: 我想使用Java 7和NIO 2编写异步服务器。 但是我应该怎么用呢? 例如,如果我开始: 然后,当我这样做时,该程序 终止, 因为该调用是 异步的 。如果我将该代码置于无限循环中,则会抛出。 关于如何使用编写一个简单的异步服务器的任何建议? 这是我的完整示例(类似于JavaDoc中的示例): 问题答案: 您走在正确的轨道上,从完成的回调中调用accept()以便接受更多连接应该起作用

  • 我刚刚开始使用Sockets,对于我当前的项目,我需要能够从客户端控制我的程序,但是如果我的项目合作伙伴想同时使用他的客户端,服务器不会向他发送“您已连接”消息,如连接类所示。所以我假设服务器不同时接受多个客户端。我尝试过使用类Connection的Thread,但这也不会向第二个客户端发送消息“您已连接”。我在这里做错了什么? 这是我用来同时连接多个用户的线程: 编辑:附加信息 在第一个客户端连

  • 我正在尝试基于非阻塞NIO消息开发自己的通信库。我已经阅读了1000篇关于它的教程和书中的章节,我认为最后我有了一些可以在几乎没有同时连接的情况下工作的东西。但是当我在服务器端有很多连接共存时,我遇到了一些问题。 我有4个私有方法的典型选择器实现:accept、finishConnect、read和write。我的问题在于前两个:接受和完成连接。 当客户端打开一个新的套接字,并且一个可接受的键唤醒

  • 德比文件说 德比。博士。主机名=主机名 该属性监听主机的网络连接,即接受来自主机的连接。如果指定了0.0.0.0,则接受来自任何主机的连接。 现在,我有三台远程计算机,,,。 我的derby服务器正在hostA上运行 所以,我写了 然而,这是行不通的。还有别的办法吗? 编辑: 当我将属性设置为 然后和不能连接到服务器。他们低于例外 JAVAsql。SQLNonTransientConnection

  • 客户端IP:客户端端口和服务器IP:服务器端口->协议(以区分TCP和UDP) 那么为什么accept()需要返回绑定到不同端口的套接字呢?每个报头中发送的四组信息是否足以区分来自不同机器的到同一服务器端口的多个连接,从而不需要使用服务器机器上的不同端口进行通信?

  • 这是在创建持久订阅的上下文中。 DefaultMessageListenerContainer中有一个setClientId(),SingleConnectionFactory中有一个。 我的理解是: < li >长期订阅适用于消费者/订户。 < li >不同的消费者应该能够使用不同的客户端id。 < li >不同的消费者应该能够共享一个连接。 < li >每个使用者有一个(ListenerCon