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


214

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

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


2
@Software Monkey:我仍然回答了这个问题,因为我希望这对将来实际上正在编写服务器的人可能有用。
derobert

1
@derobert:我看到了+1。实际上,在上一条评论之后,我有相同的想法,但以为我会保留该评论。
劳伦斯·多尔

Answers:


395

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

在客户端: 增大外围端口范围,并减小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

以上内容不应解释为影响系统每秒进行出站连接的能力的因素。但是,这些因素会影响系统在长时间的“活动”中以可持续的方式处理并发连接的能力。

默认sysctl的参数上一个典型的Linux箱tcp_tw_recycletcp_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

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

除上述以外,程序员使用的另一种比较流行的技术是减少tcp写调用的次数。我自己的偏好是使用一个缓冲区,在该缓冲区中,我将希望发送的数据推送到客户端,然后在适当的时候,将缓冲的数据写出到实际的套接字中。这种技术使我可以使用大数据包,减少碎片并降低用户域和内核级的CPU使用率。


4
辉煌的答案!我的问题有点不同,即我试图通过PHP将会话信息从应用程序级会话存储移到Redis。出于某种原因,我一口气添加不了很多睡眠就不能添加超过28230个会话,在php或redis日志中都没有看到错误。我们花了整整一整天的时间,直到我认为问题可能不在于php / redis,而在tcp / ip层中将两者联系在一起,才得出了答案。此后,我们很快就解决了这个问题:)非常感谢!
2013年

27
不要忘记我们一直在谈论IP +端口。您可以从许多不同的IP向端口XY打开“无限”套接字。470的限制仅适用于同时打开的同一IP套接字。另一个IP可以拥有到相同端口的470个连接。
Marki555 2014年

6
@ Marki555:您的评论非常正确。为生成和维持大量出站连接而开发的应用程序,必须具有对用于创建出站连接的可用IP的“感知”,然后必须使用某种“循环算法”适当地绑定到这些IP地址,并进行维护一个“记分板”。
mdk 2014年

8
这个答案有错误。首先,net.ipv4.tcp_fin_timeout仅适用于FIN_WAIT_2状态(cs.uwaterloo.ca/~brecht/servers/ip-sysctl.txt)。其次,正如@Eric所说,“在任何给定时间有470个套接字”是不正确的。
Sharvanath 2014年

3
@mdk:我不清楚这个计算部分(61000 - 32768) / 60 = 470 sockets per second。您能详细说明一下吗?
汤姆·泰勒

64

有几个变量可以设置最大连接数。最有可能的是,您首先用尽了文件编号。检查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等),请注意,成千上万的连接可能会超出其功能。

我希望这会有所帮助。您实际上是在问网络问题。


16

为了改善derobert的回答,

您可以通过设置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}'

3
which awk是您确定awk路径的朋友,SunOS也有一个链接:)
Panagiotis Moustafellos 2014年

2
@PanagiotisM。在这种情况下,您只能which依靠该程序,而无需提供完整路径。(也就是说,我不确定脚本中的解决方案是否更接近完美,但这不是脚本所要解决的问题)。PATHawk
Michael Krelin-黑客

5
我喜欢这个脚本如何弹道来确定awk位置,但是假设shell始终是/bin/bash (提示:AIX5 / 6在默认情况下甚至没有bash)。
kubanczyk

awk检测有用吗?个人而言,我会简单地假设有一个正确的PATH,但一个合理的选择可能是/usr/bin/env awk/usr/bin/env bash分别。对于它的价值,它在我的Linux系统上位置错误。它在/usr/bin/awk/bin/awk
Wolph

1
当我运行此脚本时,我得到798,这是什么意思?

10

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

从服务器端:

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

  2. 将缓慢的TCP超时转换为503快速立即响应,如果负载均衡器正常工作,则应选择要使用的工作资源,这比在发生意外错误消息时挂在那里要好。

例如:如果您使用的是节点服务器,那么您可以从npm使用太忙。实现类似:

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

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

  1. 尝试将呼叫分组,减少客户端和服务器的流量和总请求数。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.