我正在开发一些模拟网络设备的代码。我需要运行几千个模拟“代理”,每个都需要连接到一个服务。问题是在打开1023连接后,连接开始超时,整个事情都崩溃了。
主要代码在Go中,但是我编写了一个非常简单的python脚本来重现问题。
有一点不寻常的是我们需要在创建时在套接字上设置本地地址。这是因为代理连接的设备期望明显的IP与我们应该的匹配。为此,我配置了10,000个虚拟接口(eth0:1到eth0:10000)。这些在专用网络中分配了唯一的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个连接。
与使用本地地址不同的是,必须在建立连接之前进行绑定,因此在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并且我已经减少了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地址有关。
答案 0 :(得分:2)
真是个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/,它解释了如何增加限制。碰撞thresh3值立即解决了问题。
答案 1 :(得分:0)
您可能希望查看与net.ipv4相关的sysctl设置。
这些设置包括maxconntrack等内容以及您可能希望调整的其他相关设置。
答案 2 :(得分:0)
您是否绝对确定问题不在服务器端连接而不关闭套接字?即服务器进程的lsof -n -p
显示什么?服务器进程的plimit -p
显示什么?服务器端可能无法接受任何更多连接,而客户端则获得EINPROGRESS结果。
检查ulimit是否有连接两侧打开文件的数量 - 1024太接近ulimit级别是巧合。