【问题标题】:'ab' program freezes after lots of requests, why?'ab' 程序在大量请求后冻结,为什么?
【发布时间】:2010-11-16 00:29:30
【问题描述】:

每当我使用 'ab' 对 Web 服务器进行基准测试时,它会在发送大量请求后冻结一段时间,仅在 20 秒左右后继续。

考虑以下用 Ruby 编写的 HTTP 服务器模拟器:

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 基准测试。

【问题讨论】:

    标签: sockets debugging networking throttling apachebench


    【解决方案1】:

    听起来您的ephemeral ports 用完了。要检查,请使用netstat 命令并查找处于TIME_WAIT 状态的数千个端口。

    在 Mac OS X 上,默认的临时端口范围是 49152 到 65535,总共 16384 个端口。您可以使用sysctl 命令检查这一点:

    $ 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 * 最大段生命周期),直到您可以重用特定端口号。您可以通过将范围更改为从 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,某些防火墙可能会假定动态分配的端口属于该范围。您可能需要重新配置防火墙才能使用本地网络之外的更大范围。

    还可以减少最大段生命周期(Mac OS X 上的sysctl net.inet.tcp.msl),它控制TIME_WAIT 状态的持续时间,但这很危险,因为它可能导致旧连接与新连接混淆那些使用相同端口号的。还有一些技巧涉及使用 SO_REUSEADDR 选项绑定到特定端口,或使用 SO_LINGER 选项关闭,但这些也可能导致新旧连接混淆,因此通常被认为是坏主意。

    【讨论】:

    • 是的,就是这样。我按照brianp.net/2008/10/03/… 的说明更改了 MSL,现在一切正常。谢谢!
    • 非常感谢,这解决了我遇到的同样问题。
    • 在这里我认为这是一个Golang 问题.. 当它冻结来自ab 的每16000 个请求时
    【解决方案2】:

    不要增加端口的数量,而是在 Mac OS X 上更改TIME_WAIT 的长度。

    这仅在开发中有效,但我现在可以向ab 询问我想要多少请求而不会超时。

    将默认超时设置为 1000 毫秒,如下所示:

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

    另一个答案中提到的 brianp.net 页面不再可用。您可以从internet archive 检索它。

    【讨论】:

      【解决方案3】:

      解决此问题的另一个选项是通过添加 "-k" 选项来启用 HTTP KeepAlive。这将使 ab 重新使用 TCP 连接,因此它不会耗尽所有可用端口。例如:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-17
        • 1970-01-01
        • 2020-02-23
        • 2022-12-09
        • 1970-01-01
        • 2016-12-21
        • 2011-11-13
        相关资源
        最近更新 更多