我正在开发一些模拟networking设备的代码。 我需要运行几千个模拟“代理”,每个需要连接到一个服务。 问题是,打开1023连接后,连接开始超时,整个事情崩溃了。
主要的代码在Go中,但是我写了一个非常简单的python脚本来重现问题。
有一点是不寻常的是,我们需要在创build套接字时在套接字上设置本地地址。 这是因为代理商所连接的设备预计明显的IP与我们所说的应该是一致的。 为此,我configuration了10,000个虚拟接口(eth0:1到eth0:10000)。 这些在专用networking中被分配唯一的IP地址。
python脚本就是这样(只能运行到2000个连接):
import socket i = 0 for b in range(10, 30): for d in range(1, 100): i += 1 ip = "1.%d.1.%d" % (b, d) print("Conn %i %s" % (i, ip)) s = socket.create_connection(("1.6.1.1", 5060), 10, (ip, 5060))
如果我删除了socket.create_connection(源地址)的最后一个参数,那么我可以获得所有2000个连接。
与使用本地地址不同的是,在build立连接之前必须进行绑定,所以在strace下运行的程序的输出如下所示:
Conn 1023 1.20.1.33 bind(3, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0 bind(3, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("1.20.1.33")}, 16) = 0 connect(3, {sa_family=AF_INET, sin_port=htons(5060), sin_addr=inet_addr("1.6.1.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
如果我没有本地地址运行,AF_INET绑定消失,它的工作原理。
所以,似乎必须对可以制作的绑定数量有一些限制。 我已经浏览了各种关于Linux上TCP调优的链接,并且尝试过使用tcp_tw_reuse / recycle来解决问题,并且减less了fin_timeout,而且我做了其他我不记得的事情。
这是在Ubuntu Linux(11.04,内核2.6.38(64位))上运行的,它是VMWare ESX集群上的虚拟机。
就在发布之前,我尝试运行python脚本的第二个实例,并从1.30.1.1开始。 第一个脚本遍历到1023个连接,但是第二个脚本甚至不能完成第一个脚本,说明这个问题与大量的虚拟接口有关。 一些内部数据结构可能有限吗? 一些最大的记忆设置的地方?
任何人都可以想到在Linux会造成一些限制吗?
更新:
今天早上我决定尝试一个实验。 我修改了python脚本,使用“主”接口IP作为源IP,并使用临时端口范围为10000+。 脚本现在看起来像这样:
import socket i = 0 for i in range(1, 2000): print("Conn %i" % i) s = socket.create_connection(("1.6.1.1", 5060), 10, ("1.1.1.30", i + 10000))
这个脚本工作得很好,所以这增加了我的观点,即问题与大量的别名IP地址有关。
什么是DOH时刻。 我正在使用netstat监视服务器,由于我没有看到大量的连接,所以我不认为有问题。 但最后我醒来,并检查/var/log/kernel
,其中我发现这一点:
Mar 8 11:03:52 Testserver01 kernel: ipv4: Neighbour table overflow.
这导致我这个帖子: http : //www.serveradminblog.com/2011/02/neighbour-table-overflow-sysctl-conf-tunning/它解释了如何增加限制。 颠覆价值立即解决了这个问题。
你可能想看看与net.ipv4相关的sysctl设置。
这些设置包括像maxconntrack和其他相关的设置,你可能想调整。
你是否绝对肯定这个问题是不是在服务器端连接不关闭套接字? 即服务器进程的lsof -n -p
表示什么? 服务器进程的plimit -p
显示什么? 服务器端可能不能接受任何更多的连接,而客户端正在获得EINPROGRESS结果。
检查ulimit连接两端的打开文件的数量 – 1024与ulimit级别太接近是重合的。