【问题标题】:Increasing the maximum number of TCP/IP connections in Linux在 Linux 中增加最大 TCP/IP 连接数
【发布时间】:2010-09-29 11:09:09
【问题描述】:

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

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

【问题讨论】:

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

标签: linux networking linux-kernel


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    在客户端: 增加临时端口范围,减少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_recycletcp_tw_reuse 的典型 Linux 机器上的默认 Sysctl 值将是

    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 设备后面的两台不同计算机的连接,这是一个难以检测并等待咬你的问题。请注意,net.ipv4.tcp_tw_recycle 在 Linux4.12 中一直是 removed

    在服务器端: 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。你能详细说明一下吗?
    【解决方案3】:

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

    从服务器端:

    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();
    });
    

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

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

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

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

    【讨论】:

      【解决方案4】:

      为了改进 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,这是什么意思?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2023-03-07
      • 1970-01-01
      相关资源
      最近更新 更多