ChatGPT解决这个技术问题 Extra ChatGPT

在 Linux 中增加最大 TCP/IP 连接数

我正在对服务器进行编程,我的连接数似乎受到了限制,因为即使我将连接数设置为“无限”,我的带宽也没有饱和。

如何增加或消除我的 Ubuntu Linux 机器一次可以打开的最大连接数?操作系统是否限制了这一点,还是路由器或 ISP?或者是别的什么?

@Software Monkey:我还是回答了这个问题,因为我希望这对将来真正编写服务器的人有用。
@derobert:我看到了+1。实际上,在我之前的评论之后,我也有同样的想法,但我认为我会让评论保持不变。

T
Tombart

最大连接数受到客户端和服务器端的某些限制的影响,尽管略有不同。

在客户端:增加临时端口范围,并减少 tcp_fin_timeout

要找出默认值:

sysctl net.ipv4.ip_local_port_range
sysctl net.ipv4.tcp_fin_timeout

临时端口范围定义主机可以从特定 IP 地址创建的最大出站套接字数。 fin_timeout 定义了这些套接字保持 TIME_WAIT 状态(使用一次后无法使用)的最短时间。通常的系统默认值是:

net.ipv4.ip_local_port_range = 32768 61000

net.ipv4.tcp_fin_timeout = 60

这基本上意味着您的系统不能始终保证每秒超过 (61000 - 32768) / 60 = 470 个套接字。如果您对此不满意,可以从增加 port_range 开始。如今,将范围设置为 15000 61000 很常见。您可以通过减小 fin_timeout 来进一步提高可用性。假设您两者都做,您应该更容易看到每秒超过 1500 个出站连接。

要更改值:

sysctl net.ipv4.ip_local_port_range="15000 61000"
sysctl net.ipv4.tcp_fin_timeout=30

以上不应解释为影响系统每秒建立出站连接能力的因素。但是,这些因素会影响系统在大量“活动”期间以可持续的方式处理并发连接的能力。

tcp_tw_recycle & 的典型 Linux 机器上的默认 Sysctl 值tcp_tw_reuse 将是

net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_reuse=0

这些不允许来自“已使用”套接字(处于等待状态)的连接,并强制套接字持续完整的 time_wait 周期。我建议设置:

sysctl net.ipv4.tcp_tw_recycle=1
sysctl net.ipv4.tcp_tw_reuse=1 

这允许在 time_wait 状态下快速循环套接字并重新使用它们。但在您进行此更改之前,请确保这不会与您将用于需要这些套接字的应用程序的协议冲突。请务必阅读帖子 "Coping with the TCP TIME-WAIT" from Vincent Bernat 以了解其含义。 net.ipv4.tcp_tw_recycle 选项对于面向公众的服务器来说是一个很大的问题,因为它无法处理来自同一 NAT 设备后面的两台不同计算机的连接,这是一个难以检测并等待着你的问题。请注意,从 Linux 4.12 开始,net.ipv4.tcp_tw_recycleremoved

在服务器端: net.core.somaxconn 值具有重要作用。它限制排队到侦听套接字的最大请求数。如果您确定服务器应用程序的能力,请将其从默认的 128 提高到 128 到 1024 之类的值。现在您可以通过将应用程序的侦听调用中的侦听积压变量修改为相等或更高的整数来利用这种增加。

sysctl net.core.somaxconn=1024

txqueuelen 您的以太网卡的参数也有一定的作用。默认值为 1000,因此如果您的系统可以处理,请将它们提高到 5000 甚至更多。

ifconfig eth0 txqueuelen 5000
echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local

同样提高 net.core.netdev_max_backlognet.ipv4.tcp_max_syn_backlog 的值。它们的默认值分别为 1000 和 1024。

sysctl net.core.netdev_max_backlog=2000
sysctl net.ipv4.tcp_max_syn_backlog=2048

现在请记住通过在 shell 中增加 FD ulimts 来启动客户端和服务器端应用程序。

除了上述之外,程序员使用的一种更流行的技术是减少 tcp write 调用的数量。我自己的偏好是使用缓冲区,在其中我将希望发送到客户端的数据推送到客户端,然后在适当的时候将缓冲的数据写出到实际的套接字中。这种技术允许我使用大数据包,减少碎片,降低我在用户空间和内核级别的 CPU 利用率。


绝妙的答案!我的问题有点不同,即我试图通过 PHP 将会话信息从应用程序级会话存储移动到 redis。出于某种原因,我不能一次添加超过 28230 个会话,而不会一次添加大量睡眠,并且在 php 或 redis 日志中都没有看到错误。我们为此花了一整天的时间,直到我认为问题可能不在于 php/redis,而在于连接两者的 tcp/ip 层并得出了这个答案。在那之后很快就解决了这个问题:)非常感谢!
不要忘记我们一直在谈论 IP+端口。您可以从许多不同的 IP 向端口 XY 打开“无限”套接字。 470 的限制仅适用于同一 IP 的并发打开的套接字。另一个 IP 可以有自己的 470 连接到相同的端口。
@Marki555:您的评论非常正确。为生成和维持大量出站连接而开发的应用程序必须“了解”用于创建出站连接的可用 IP,然后必须使用某种“循环算法”适当地绑定到这些 IP 地址,并维护一个“记分牌”。
这个答案有错误。首先,net.ipv4.tcp_fin_timeout 仅适用于 FIN_WAIT_2 状态 (cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt)。其次,正如@Eric 所说,“在任何给定时间都有 470 个套接字”是不正确的。
@mdk:我不清楚这个计算部分 (61000 - 32768) / 60 = 470 sockets per second。你能详细说明一下吗?
j
jamix

有几个变量可以设置最大连接数。最有可能的是,您首先用完了文件编号。检查ulimit -n。之后,/proc中有设置,但默认为数万。

更重要的是,听起来你做错了什么。单个 TCP 连接应该能够使用两方之间的所有带宽;如果不是:

检查您的 TCP 窗口设置是否足够大。 Linux 默认值适用于除真正快速的 inet 链接(数百 mbps)或快速卫星链接之外的所有内容。您的带宽*延迟积是多少?

使用 ping 大数据包检查数据包丢失(ping -s 1472 ...)

检查速率限制。在 Linux 上,这是用 tc 配置的

使用例如 iperf 确认您认为存在的带宽确实存在

确认您的协议是健全的。记住延迟。

如果这是一个千兆+ LAN,您可以使用巨型数据包吗?你是?

可能我理解错了。也许你正在做类似 Bittorrent 的东西,你需要大量的连接。如果是这样,您需要弄清楚您实际使用了多少个连接(尝试 netstatlsof)。如果这个数字很大,您可以:

有很多带宽,例如 100mbps+。在这种情况下,您实际上可能需要增加 ulimit -n。尽管如此,大约 1000 个连接(我的系统上的默认值)还是相当多的。

有网络问题会减慢您的连接速度(例如,数据包丢失)

有其他东西会减慢您的速度,例如 IO 带宽,特别是如果您正在寻找。你检查过iostat -x 吗?

此外,如果您使用的是消费级 NAT 路由器(Linksys、Netgear、DLink 等),请注意,您可能会因数千个连接而超出其能力。

我希望这能提供一些帮助。你真的在问一个网络问题。


e
emilianofs

为了改进@derobert 给出的答案,

您可以通过 catting nf_conntrack_max 确定您的操作系统连接限制。例如:

cat /proc/sys/net/netfilter/nf_conntrack_max

您可以使用以下脚本来计算与给定 tcp 端口范围的 TCP 连接数。默认情况下 1-65535

这将确认您是否正在最大化您的操作系统连接限制。

这是脚本。

#!/bin/bash
OS=$(uname)

case "$OS" in
    'SunOS')
            AWK=/usr/bin/nawk
            ;;
    'Linux')
            AWK=/bin/awk
            ;;
    'AIX')
            AWK=/usr/bin/awk
            ;;
esac

netstat -an | $AWK -v start=1 -v end=65535 ' $NF ~ /TIME_WAIT|ESTABLISHED/ && $4 !~ /127\.0\.0\.1/ {
    if ($1 ~ /\./)
            {sip=$1}
    else {sip=$4}

    if ( sip ~ /:/ )
            {d=2}
    else {d=5}

    split( sip, a, /:|\./ )

    if ( a[d] >= start && a[d] <= end ) {
            ++connections;
            }
    }
    END {print connections}'

which awk 是您确定 awk 路径的朋友,SunOS 也有指向它的链接 :)
@PanagiotisM。 which 依赖于位于 PATH 中的程序,在这种情况下,您可以只使用 awk 而不是提供完整路径。 (也就是说,我不确定脚本中的解决方案是否更接近完美,但这不是脚本的内容)。
我喜欢这个脚本如何通过弹道确定 awk 位置,但假定 shell 始终是 /bin/bash(专业提示:AIX5/6 默认情况下甚至没有 bash)。
awk 检测有用吗?就我个人而言,我只是假设有一个正确的 PATH,但一个合理的替代方案可能分别是 /usr/bin/env awk/usr/bin/env bash。对于它的价值,它在我的 Linux 系统上的位置错误。它在 /usr/bin/awk 而不是 /bin/awk
当我运行这个脚本时,我得到 798,这是什么意思?
K
Kev

在应用程序级别,开发人员可以执行以下操作:

从服务器端:

检查负载均衡器(如果有)是否正常工作。将慢速 TCP 超时转换为 503 快速即时响应,如果您的负载均衡器正常工作,它应该选择工作资源来提供服务,这比挂在那里有意外的错误消息要好。

例如:如果你使用的是节点服务器,你可以从 npm 使用 toobusy。实现类似:

var toobusy = require('toobusy');
app.use(function(req, res, next) {
  if (toobusy()) res.send(503, "I'm busy right now, sorry.");
  else next();
});

为什么是 503?以下是一些关于过载的好见解:http://ferd.ca/queues-don-t-fix-overload.html

我们也可以在客户端做一些工作:

尝试对呼叫进行批量分组,减少客户端和服务器的流量和总请求数。尝试构建一个缓存中间层来处理不必要的重复请求。