Git   发布时间:2022-04-04  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了我们是否应该使用多个接受者套接字来接受大量的连接?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

众所周知,SO_REUSEPORT允许多个套接字在相同的IP地址和端口组合上进行监听 ,每秒增加2到3次 ,并减less延迟(〜30%)和延迟(8次)的标准差: https ://www.Nginx.com/blog/socket-sharding-Nginx-release-1-9-1/

Nginx版本1.9.1引入了一个新特性,可以使用SO_REUSEPORT套接字选项,这个选项可以在很多操作系统的新版本中使用,包括DragonFly BSD和Linux(内核版本3.9和更高版本) 。 此套接字选项允许多个套接字侦听相同的IP地址和端口组合 。 内核然后通过套接负载平衡传入的连接。 …

如图所示, 重新使用端口每秒增加2到3次请求,并减less延迟延迟的标准偏差。

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

当从另一个线程closures套接字时,阻塞recv不会退出

为什么Windows Java不能绑定到已绑定的端口?

Linux,了解setsockopt()PACKET_FANOUTnetworking缩放

无法绑定到多播地址(Windows)

/ proc中可能的内部套接字状态列表

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

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

SO_REUSEPORT可用于大多数现代操作系统 :Linux(自2013年4月29日起 内核> = 3.9 ),Free / Open / NetBSD,MacOS,iOS / watchOS / tvOS, IBM AIX 7.2 , Oracle Solaris 11.1 ,Windows(仅为SO_REUSEPORT , 2个标志SO_REUSEPORT + SO_REUSEADDR在BSD中),并可能在Android上 : https : //stackoverflow.com/a/14388707/1558037

Linux> = 3.9

此外,内核对SO_REUSEPORT套接字执行一些在其他操作系统中找不到的“特殊魔力”:对于UDP套接字,它试图平均地分配数据报,对于TCP侦听套接字,它试图分发传入的连接请求 accept() )平均分配到所有共享相同地址和端口组合的套接字。 因此,应用程序可以轻松地在多个subprocess中打开相同的端口,然后使用SO_REUSEPORT获得非常便宜的负载平衡

另外,为了避免旋转锁的locking并实现高性能,不应该有读取多于一个线的插槽。 即每个线程应该处理自己的套接字进行读/写。

accept()是同一个套接字描述符的线程安全函数,所以它应该被锁保护 – 所以锁争用降低了性能 : http : //unix.derkeiler.com/Newsgroups/comp.unix.programmer/2007-06/ msg00246.html

POSIX.1-2001 / SUSv3 需要accept(),bind(),connect(),listen(),socket(),send(),recv()等为线程安全函数 关于它们与线程的交互,标准中可能存在一些含糊之处,但是其意图是它们在multithreading程序中的行为是由标准来pipe理的。

如果我们从多个线程使用相同的一个套接字,那么性能将会很低,因为套接字通过锁来保护multithreading的线程安全访问: https : //blog.cloudflare.com/how-to-receive-a-million-包/

与单线程程序相比,接收性能下降。 这是由UDP接收缓冲区上的锁争用引起的 。 由于两个线程都使用相同的套接字描述符,所以他们花费了大量的时间争取UDP接收缓冲区的locking。 本文更详细地描述了这个问题。

有关应用程序尝试从套接字读取数据时的自旋locking的更多详细信息 – “Linux UDP套接字并发性能分析”: http : //www.jcc2014.ucm.cl/jornadas/WORKSHOP/WSDP%202014/WSDP-4 .PDF

V. K ERNEL隔离

….

另一方面, 当应用程序试图从套接字读取数据时 ,它执行一个类似的过程,如下所示,从右到左如图3所示:

1) 使用相应的自旋锁 (绿色)从接收队列中取出一个或多个数据包。

2)将信息复制到用户空间内存。

3)释放数据包使用的内存。 这可能会改变套接字的状态,所以可能会发生两种locking套接字的方法快速和慢速。 在这两种情况下,数据包都与套接字断开连接,“记忆计数”统计信息将更新,并根据所采用的lockingpath释放套接字。

也就是说,当许multithreading访问相同的套接字时,由于等待一个自旋锁,性能会降低。

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

我们使用RFS和XPS – 即在同一个cpu-Core上为应用程序线程(用户空间)处理相同连接的TCP / IP堆栈(内核空间)。

至less有三种方法可以接受连接,以便在多个线程中进行处理:

使用一个在许multithreading之间共享的接受者套接 ,并且每个线程接受连接并处理它

一个线程中使用一个接受者套接 ,并且该线程通过使用线程安全队列来推送接收到的与其他线程工作者的连接的套接字描述符

使用许多接收者套接 ,它们在每个线程中监听相同的ip:port ,1个单独的acceptor套接字,接收连接的线程将处理它(recv / send)

什么是更有效的方式,如果我们接受很多新的TCP连接?

I / O的最新Windows线程池API使用情况

不稳定的tcp接收次数

避免在multithreading套接字应用程序中重复使用相同的fd号码

听多次调用套接字 – 预期的行为?

重复使用WinSocket客户端/服务器应用程序的套接

在生产中必须处理这样的场合,这是解决这个问题的好方法

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

将该内核标记为未使用, 然后在您的代码中通过cpuset显式请求“侦听套接字”线程。

接下来,建立一个队列(理想情况下,一个优先级队列),优先写入操作(即“第二个读写器问题)。现在,设置很多工作线程,你认为合理。

在这一点上,“传入连接”线程的目标应该是:

accept()传入的连接。

尽可能快地将这些连接文件描述符(FD)传递给作者优先级队列结构。

尽快回到accept()状态。

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

这也会阻止“监听套接字”线程和工作线程同时访问相同的队列,这将使您免受最糟糕的情况,比如缓慢的工作线程在“监听套接字”线程时锁定队列想要放下数据。 即

Incoming client connections || || listner thread - accept() connection. / listner/Helper queue || || Helper thread / Shared Worker queue || || Worker thread #n / Worker-specific memory space. read() from client.

至于你提出的其他两个选项:

使用一个在许多线程之间共享的接受者套接字,并且每个线程接受连接并处理它。

乱。 线程将不得不轮流发出accept()调用,这样做没有任何好处。 你还将有一些额外的顺序逻辑来处理哪个线程的“转向”。

使用许多接收者套接字,它们在每个线程中监听相同的ip:port,1个单独的接受者套接字,接收连接的线程将处理它(recv / send)

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

假设你有两个10Gbps的网络连接,并假设一个500byte的平均帧大小(这是非常保守的一个服务器没有交互使用),你将有每个网卡每秒约2Mpackets(我不相信你有超过这个)这意味着每微秒处理4个数据包。 这对于你的配置中描述的cpu来说是非常慢的延迟。 在这些地方,我要确保你的瓶颈将会在网络(和你连接的交换机)中,而不是在每个socket上的自旋锁(在自旋锁上需要一些cpu周期来解决,这远远超出了由网络)。 不管怎么说,我会在每张网卡上专用一两个线程(一个用于读取,另外一个用于写入),并且不要在套接字锁定功能中多加考虑。 最有可能的是你的瓶颈是你在这个配置的后端应用软件。

即使在遇到麻烦的情况下,也许最好对内核软件进行一些修改,而不是增加越来越多的处理器,或者考虑将自旋锁分布到不同的套接字中。 或者甚至更好,增加更多的网卡来消除瓶颈。

使用许多接收者套接字,它们在每个线程中监听相同的ip:port,1个单独的接受者套接字,接收连接的线程将处理它(recv / send)

在TCP中这是不可能的。 算了吧。

做别人做的事。 一个接受线程,它根据接受的套接字启动一个新的线程,或者将它们分派给一个线程池。

大佬总结

以上是大佬教程为你收集整理的我们是否应该使用多个接受者套接字来接受大量的连接?全部内容,希望文章能够帮你解决我们是否应该使用多个接受者套接字来接受大量的连接?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: