2009-08-01 51 views
32

每当我使用'ab'来对一个web服务器进行基准测试时,它会在发送很多请求后冻结一段时间,只有在20秒左右之后才会继续。'ab'程序在多次请求后会冻结,为什么?

考虑下面的HTTP服务器仿真器,用Ruby写的:

require 'socket' 

RESPONSE = "HTTP/1.1 200 OK\r\n" + 
      "Connection: close\r\n" + 
      "\r\n" + 
      "\r\n" 

buffer = "" 
server = TCPServer.new("127.0.0.1", 3000) # Create TCP server at port 3000. 
server.listen(1024)      # Set backlog to 1024. 
while true 
    client = server.accept    # Accept new client. 
    client.write(RESPONSE)    # Write a stock "HTTP" response. 
    client.close_write     # Shutdown write part of the socket. 
    client.read(nil, buffer)   # Read all data from the socket. 
    client.close      # Close it. 
end 

我然后运行AB如下:

ab -n 45000 -c 10 http://127.0.0.1:3000/ 

在最初的几秒钟,AB,它的工作,因为它的应该并且使用100%的CPU:

Benchmarking 127.0.0.1 (be patient) 
Completed 4500 requests 
Completed 9000 requests 
Completed 13500 requests 

约13500的请求后,系统CPU使用率下降吨○0%。 ab似乎被冻结在某物上。问题不在服务器中,因为此时服务器正在调用accept()。大约20秒后ab继续,好像什么也没有发生,并且会再次使用100%的CPU,只有在几秒钟后再次冻结。

我怀疑内核中的东西是限制连接,但是什么?为什么?我使用的是OS X Leopard。我也在Linux上看到过类似的行为,尽管冻结发生在更多的请求中,并且不经常发生。

此问题阻止我运行大型HTTP基准测试。

回答

47

这听起来像你用完ephemeral ports。要检查,请使用netstat命令,并在TIME_WAIT状态中查找数千个端口。

在Mac OS X上,默认临时端口范围是49152到65535,总共16384个端口。

 
$ sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last 
net.inet.ip.portrange.first: 49152 
net.inet.ip.portrange.last: 65535 

一旦你用完了临时端口,你通常需要等到TIME_WAIT状态期满(2 *最大段寿命),直到你可以重复使用一个特定的端口号:你可以用sysctl命令检查此。通过将范围从32768开始更改为Linux和Solaris的默认值,您可以将端口数加倍。 (最大端口号是65535所以不能增加的高端。)

 
$ sudo sysctl -w net.inet.ip.portrange.first=32768 
net.inet.ip.portrange.first: 49152 -> 32768 

注意,official range designated by IANA是49152至65535,和一些防火墙可以假设动态分配的端口落入该范围内。您可能需要重新配置防火墙,以便在本地网络之外使用更大的范围。

也可以降低最大片段生命周期(sysctl net.inet.tcp.msl在Mac OS X),其控制TIME_WAIT状态的持续时间,但这是危险的,因为它可能会导致旧的连接弄混了较新的是使用相同的端口号。还有一些涉及通过SO_REUSEADDR选项绑定到特定端口的技巧,或者通过SO_LINGER选项关闭,但这些技巧也可能导致旧的和新的连接混在一起,所以通常被认为是不好的想法。

+1

是的,就是这样。我按照http://www.brianp.net/2008/10/03/changing-the-length-of-the-time_wait-state-on-mac-os-x/上的说明更改了MSL,并且一切正常现在。谢谢! – Hongli 2009-08-02 11:58:38

16

除了增加端口数量,改变TIME_WAIT长度在Mac OS X

发展这只适用,但现在我可以问ab尽可能多的请求,因为我想不会超时。

设置默认的超时到1000毫秒,像这样:

$ sudo sysctl -w net.inet.tcp.msl=1000 
net.inet.tcp.msl: 15000 -> 1000 

在对方的回答中提到的brianp.net页面不再可用。您可以从internet archive检索它。

相关问题