我看到一些奇怪的行为试图预热使用java.net.Socket
进行连接的连接池。
这是一个连接大量套接字的小程序:
public class SocketTest {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 4000; i++) {
long t = System.currentTimeMillis();
new Socket("localhost", 3306);
long total = System.currentTimeMillis() - t;
if (total > 10)
System.out.format("%5d %dms\n", i, total);
}
}
}
我在机器上的开放端口上尝试了这个。
MySQL的:
0 34ms
468 1000ms
676 997ms
831 998ms
970 997ms
...
IPP:
0 41ms
231 998ms
232 998ms
233 999ms
234 999ms
236 3002ms
238 3002ms
240 3002ms
...
eJabberd(xmpp服务器):
0 45ms
27 998ms
42 999ms
81 997ms
99 1000ms
120 997ms
135 998ms
147 997ms
MongoDB的:
0 73ms
1314 999ms
1791 998ms
2098 999ms
2466 1000ms
2717 1000ms
nginx 不会出现此行为(并且连接速度非常快)。
在多线程测试中,我总是只看到非常接近1000毫秒,3000毫秒,7000毫秒或15000毫秒的数字。
在套接字连接之间放置Thread.sleep(50)
会延迟一段时间内发生的行为。
我最初在Windows上观察到这种行为,但上面的内容在XUbuntu 14.04上进行了测试。
我分析了应用程序,花费在PlainSocketImpl.socketConnect()
上的时间,该时间委托给unix系统上的OS本机方法。
我也尝试过使用Oracle JDK 8和OpenJDK 7,并获得相同的结果。
数字的一致性使我认为它是操作系统层的某种限制或调度行为,而不是内置于服务器中的内容。
在较小的情况下,例如连接100个插座,总时间可能是10秒,但在Thread.sleep(10)
之间下降到2秒。
任何人都能解释一下吗?
编辑:使用Windows尝试过。有时获得相似的数字(3000),有时会得到零星的500毫秒。针对Windows上的MySQL,问题根本不会发生。再次,快速Thread.sleep(20)
会产生更好的性能,特别是对远程机器。
我猜这是故意的操作系统限制行为,但是想听听熟悉OS堆栈的人的意见。