Linux上的套接字最大数量

7
看起来服务器的socket限制为32720个... 我已经尝试了所有已知的变量更改以提高此限制。 但即使仍有4 GB的空闲内存和80%的空闲CPU,服务器仍然受到32720个打开的sockets的限制...
以下是配置:
~# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 63931
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 798621
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 2048
cpu time               (seconds, -t) unlimited
max user processes              (-u) 63931
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

net.netfilter.nf_conntrack_max = 999999
net.ipv4.netfilter.ip_conntrack_max = 999999
net.nf_conntrack_max = 999999

有什么想法吗?

只是说一下:如果你需要一次使用超过32000个套接字,那么你面临的问题比这个数字太低要更大。一个正常的服务器不会同时打开超过几百个套接字(对于繁忙的服务器可能会有几千个)。 - cHao
1
几百个套接字?你从哪里得到这个数字的? - TheSquad
@TheSquad:你加载了一些安全框架,限制了fd或连接的数量吗? - mvds
@cHao:这不是一个Web服务器,IRC服务器比我们的软件消耗更多的性能。假设有2K个客户端连接到IRC服务器,CPU使用率接近100%,我不是在谈论内存... - TheSquad
你知道的,如果我们不考虑需要这么多套接字的程序中明显的缺陷,那么这就成为了一个管理员问题。投票移动到Serverfault。 - cHao
显示剩余5条评论
8个回答

7

如果您正在处理 OpenSSL 和线程,请检查 /proc/sys/vm/max_map_count 并尝试提高它。


4
在IPV4中,TCP层有16位用于目标端口,16位用于源端口。
参见http://en.wikipedia.org/wiki/Transmission_Control_Protocol
看到您的限制是32K,我预计您实际上看到的是您可以进行的出站TCP连接的限制。您应该能够获得最多65K个套接字(这将是协议的限制)。这是命名连接的总数限制。幸运的是,仅为传入连接绑定端口只使用1个。但是,如果您尝试从同一台机器测试连接数量,则只能拥有65K个总出站连接(对于TCP)。要测试传入连接的数量,您需要多台计算机。
注意:您可以调用socket(AF_INET,...),直到可用文件描述符的数量,但是您不能绑定它们而不增加可用端口的数量。要增加范围,请执行以下操作:
echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range (cat它以查看当前情况--默认值为32768到61000)
也许现在是时候推出一种新的类TCP协议,允许32位源端口和目标端口了?但是有多少应用程序真正需要超过65,000个出站连接呢?
以下内容将允许Linux Mint 16(64位)上的100,000个传入连接 (您必须以root身份运行它来设置限制)
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>

void ShowLimit()
{
   rlimit lim;
   int err=getrlimit(RLIMIT_NOFILE,&lim);
   printf("%1d limit: %1ld,%1ld\n",err,lim.rlim_cur,lim.rlim_max);
}

main()
{
   ShowLimit();

   rlimit lim;
   lim.rlim_cur=100000;
   lim.rlim_max=100000;
   int err=setrlimit(RLIMIT_NOFILE,&lim);
   printf("set returned %1d\n",err);

   ShowLimit();

   int sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
   sockaddr_in maddr;
   maddr.sin_family=AF_INET;
   maddr.sin_port=htons(80);
   maddr.sin_addr.s_addr=INADDR_ANY;

   err=bind(sock,(sockaddr *) &maddr, sizeof(maddr));

   err=listen(sock,1024);

   int sockets=0;
   while(true)
   {
      sockaddr_in raddr;
      socklen_t rlen=sizeof(raddr);
      err=accept(sock,(sockaddr *) &raddr,&rlen);
      if(err>=0)
      {
        ++sockets;
        printf("%1d sockets accepted\n",sockets);
      }
   }
}

2

1
除非是由知名公司制作或做了一些不正当的事情,否则自定义服务器应用程序不会获得32k个同时客户端。在第一种情况下,您不需要帮助--不理解扩展问题的人不会被雇用。 - cHao
1
然后就说胡话吧,我不必为了从你那里得到答案而证明自己...... 这个问题众所周知很棘手,我甚至不确定是否有人能够给出一个好的答案(服务器最多可以处理多少个套接字...)。 事实是我们有超过32K的连接正在进行,只是每个服务器都被限制在32K。现在,通过所有集群服务器,我们确实拥有超过100万个连接。我们正在寻找降低服务器数量的解决方案。就是这样! - TheSquad
嗯,是的,你必须证明自己才能从我这里得到答案。SO不付给我钱——我在这里是因为我喜欢解决问题。然而,我不喜欢帮助人们解决错误的问题——到目前为止,问题似乎更多地是关于在一个盒子上拥有32k+同时长期连接的所谓要求,而不是内核和/或运行时限制,几乎没有人知道存在。所以除非我看到那是必要的,否则我会继续说“使用更少的套接字”。 - cHao
@nos: 一直保持连接吗?我不是说为32k客户提供服务是不寻常的--Google或MS的网络统计数据会让这个数字看起来相对微不足道--但是在我个人经验中,让这么多客户同时连接到一台机器上确实很不寻常。 - cHao
@nos: 是的,它正在使用线程,pthread... 但这不是问题所在。 @cHao: 我不确定你是否想要帮助,更多地是理解我们所做的事情涉及到这么多客户端,哈哈... - TheSquad
显示剩余10条评论

2

使用以下命令检查运行进程的真实限制。

cat /proc/{pid}/limits

nofiles的最大值由内核决定,以下命令以root身份执行将其增加到100,000个“文件”,即100k CC。

echo 100000 > /proc/sys/fs/file-max

要使其永久生效,请编辑/etc/sysctl.conf文件

fs.file-max = 100000

您需要让服务器请求更多的打开文件,不同的服务器设置方法也不同。例如在nginx中,您需要设置:
worker_rlimit_nofile 100000;

重新启动nginx并检查/proc/{pid}/limits。
为了测试这个,你需要在客户端中有10万个套接字,你在测试中受限于每个IP地址的TCP端口数量。
为了将本地端口范围增加到最大值...
echo "1024 65535" > /proc/sys/net/ipv4/ip_local_port_range

这给你大约64000个端口进行测试。

如果这还不够,你需要更多的IP地址。在本地测试时,你可以将源/客户端绑定到127.0.0.1 / localhost以外的IP。

例如,你可以将测试客户端绑定到从127.0.0.1到127.0.0.5随机选择的IP。

使用apache-bench,你可以设置

-B 127.0.0.x

Node.js中的套接字将被使用。

localAddress

/etc/security/limits.conf配置PAM,通常对服务器无关紧要。

如果服务器使用TCP代理请求,并使用upstream或mod_proxy等进行代理,该服务器受ip_local_port_range限制。这很容易达到32,000的限制。


1

如果您正在考虑一个应用程序,其中您认为需要打开数千个套接字,那么您肯定会想要阅读关于C10k问题的内容。该页面讨论了在将客户端连接数量扩展到单个服务器时,您将面临的许多问题。


C10K问题始于2003年... 当32000个客户端连接时,服务器仍具有良好的性能,它可以处理更多的连接,相信我! - TheSquad
1
你不觉得一个七年前的问题在今天的Core I7 8Go RAM和两个1Go网络中仍然很重要吗?就像我在第一篇帖子中所说,有32720个客户端连接时,CPU的使用率仍然低于10%,而可用内存足以打开更多连接(4Go)。以下是一些ifstat行 eth0 KB/s in KB/s out 89.22 145.37 126.97 136.15 104.11 158.18 84.17 123.62 90.64 106.47 93.17 125.98 97.21 130.69 - TheSquad
@TheSquad,aha,以及大多数TCP堆栈是30年前编写的。内存容量不涉及其中,而是客户端端口范围问题。显然您对此一无所知,因此请自行斟酌并听取有经验的人的建议。 - Nikolai Fetissov
给自己一个好处,阅读这篇文章:http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-1 有经验的人... - TheSquad
我指出了RAM,因为每个连接都是SSL,而SSL会话需要RAM... - TheSquad

0
在 net/socket.c 中,fd 是在 sock_alloc_fd() 中分配的,该函数调用 get_unused_fd()。
查看 linux/fs/file.c,fd 数量的唯一限制是 sysctl_nr_open,它被限制为
int sysctl_nr_open_max = 1024 * 1024; /* raised later */

/// later...
sysctl_nr_open_max = min((size_t)INT_MAX, ~(size_t)0/sizeof(void *)) &
                         -BITS_PER_LONG;

可以使用sysctl fs.nr_open来读取,这里默认为1M。所以文件描述符可能不是你的问题。

编辑你可能已经检查过了,但你愿意分享一下输出吗?

#include <sys/time.h>
#include <sys/resource.h>
int main() {
    struct rlimit limit;
    getrlimit(RLIMIT_NOFILE,&limit);
    printf("cur: %d, max: %d\n",limit.rlim_cur,limit.rlim_max);
}

和我们一起吗?


是的,文件描述符没问题,这是我检查的第一件事... 我更关心端口,但即使在这里也应该有大约32000个以上的可用端口。 - TheSquad
端口也应该没问题。如果你正在运行一个服务器,它应该在一个端口上监听,所有的客户端都会连接到同一个端口号。只有少数协议工作方式不同 -- FTP 是我能想到的唯一一个 -- 这是因为它使用一个单独的套接字进行数据传输。 - cHao
@mvds:结果对于两者都是798621。 - TheSquad
1
如果您需要每个客户端一个端口,请增加端口范围并使用多个IP。在2字节中只有64k个端口;-) - mvds
@mvds:我知道,端口范围已经增加了,但即使在那里,我们也没有达到64K的限制,只有32K而已... 不过,有可能将服务绑定到其他本地地址,所以实际上并不是什么问题... - TheSquad
显示剩余2条评论

0
在Gnu+Linux上,最大值是您编写的内容。这个数字(可能)在网络标准的某个地方说明。我怀疑你真的不需要那么多套接字。您应该优化使用套接字的方式,而不是一直创建许多套接字。

不,套接字只是一种有限的资源。客户端正在使用套接字。套接字并不等同于连接的客户端,也不是每个客户端都需要自己的套接字。这取决于协议。例如,TCP 需要这样的关联(1 套接字 - 1 客户端),但 UDP 不需要。即使使用 TCP,谁说连接必须是连续的呢? - skalee
1
我的意思是,在我们的软件中,一个客户端等同于一个套接字... 我们使用SSL,所以UDP不可能,而且连接需要连续... - TheSquad

0
通常来说,拥有太多的活动连接是一件坏事。然而,一切都取决于应用程序以及它与客户端进行通信的模式。
我想当客户端需要永久异步连接时,这可能是分布式解决方案能够工作的唯一方式。
假设当前负载下没有内存/ CPU/网络瓶颈,并且记住保持空闲打开的连接是分布式应用程序消耗更少资源(比如连接时间和整体/峰值内存)的唯一方法,那么总体操作系统网络性能可能会高于我们所知的最佳实践。
这是一个很好的问题,需要找到一个解决方案。问题是没有人能回答这个问题。我建议使用分而治之的技术,当找到瓶颈时再向我们反馈。
请将您的应用程序拆分并在测试环境中找到瓶颈。

1
嗨,这个问题已经两年了,当然,我已经多次超过了这个限制...实际上,Linux内核会受到的真正限制是文件描述符(打开的文件)的数量...这是唯一的限制。套接字的限制实际上是每个IP 32768个。现在我有一个使用Erlang的工作服务器,连接了接近200万用户。 - TheSquad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接