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

我正在编程一个服务器,似乎我的连接数量是有限的,因为我的带宽没有饱和,即使我已经将连接数量设置为“无限”。

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

541635 次浏览

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

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

  • 检查TCP窗口设置是否足够大。Linux默认值适用于所有情况,除了真正快速的inet链接(数百mbps)或快速卫星链接。你的带宽*延迟乘积是多少?
  • 使用ping大数据包检查数据包丢失(ping -s 1472…)
  • 检查速率限制。在Linux上,这是通过tc配置的
  • 确认你认为存在的带宽确实存在,例如,iperf
  • 确认你的方案是正常的。记得延迟。
  • 如果这是一个千兆+局域网,你可以使用巨型数据包吗?是吗?

可能是我误会了。也许你正在做一些像Bittorrent这样的事情,你需要很多连接。如果是这样,你需要弄清楚你实际使用了多少个连接(尝试netstatlsof)。如果这个数字很大,你可能会:

  • 有很大的带宽,例如100mbps+。在这种情况下,你可能实际上需要向上ulimit -n。不过,大约1000个连接(在我的系统上是默认的)是相当多的。
  • 网络问题使你的连接变慢(例如,丢包)
  • 使用其他减慢速度的东西,例如IO带宽,特别是如果您正在寻求。你检查过iostat -x吗?

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

我希望这能提供一些帮助。你其实是在问一个社交问题。

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

客户端: 增加临时端口范围,并减少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

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

典型Linux机器上的默认Sysctl值tcp_tw_recycle &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状态下快速循环套接字并重用它们。但是在进行此更改之前,请确保这与需要这些套接字的应用程序将使用的协议不冲突。确保阅读后Vincent Bernat的“处理TCP TIME-WAIT”以理解其含义。net.ipv4.tcp_tw_recycle 选项对于面向公共的服务器来说是很有问题的,因为它不能处理来自同一NAT设备后面两台不同计算机的连接,这是一个很难发现的问题,等待着咬你。注意,net.ipv4.tcp_tw_recycle已经从Linux 4.12变成了删除

服务器端: net.core.somaxconn值有一个重要的角色。它限制侦听套接字排队的最大请求数。如果您确信您的服务器应用程序的能力,可以将它从默认的128提高到像128到1024这样的值。现在,您可以通过修改应用程序的listen调用中的listen backlog变量来利用这一增加,使其等于或更高的整数

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极限来启动客户端和服务器端应用程序。

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

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

你可以通过调用nf_conntrack_max来确定你的操作系统连接限制。例如:

cat /proc/sys/net/netfilter/nf_conntrack_max

您可以使用下面的脚本计算到给定TCP端口范围的TCP连接数。默认为1-65535

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

这是剧本。

#!/bin/sh
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}'

在应用程序层面,开发者可以做以下事情:

服务器端:

  1. 检查负载均衡器(如果有)是否工作正常。

  2. 把慢的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();
});
< p >为什么是503年?这里有一些关于过载的好见解: http://ferd.ca/queues-don-t-fix-overload.html < / p >

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

  1. 尝试批量分组调用,减少客户端和服务器之间的流量和总请求数。

  2. 尝试构建一个缓存中间层来处理不必要的重复请求。

我试图在2022年在负载均衡器上解决这个问题,我发现的一种方法是将另一个IPv4(或最终IPv6)附加到NIC,所以限制现在翻了一番。当然,您需要为试图连接到机器的服务配置第二个IP(在我的例子中是另一个DNS条目)。