为什么简单的瘦服务器在基准测试时会在 16500 个请求时停止响应?

发布于 2025-01-02 23:18:11 字数 1612 浏览 1 评论 0原文

可能的重复:
“ab”程序在收到大量请求后冻结,为什么?

这是一个简单的测试服务器:

require 'rubygems'
require 'rack'
require 'thin'

class HelloWorld

  def call(env)
    [200, {"Content-Type" => "text/plain"}, "OK"]
  end
end

Rack::Handler::Thin.run HelloWorld.new, :Port => 9294 
#I've tried with these added too, 'rack.multithread' => true, 'rack.multiprocess' => true

这是一个测试运行:

$ ab -n 20000 http://0.0.0.0:9294/sdf
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 0.0.0.0 (be patient)
Completed 2000 requests
Completed 4000 requests
Completed 6000 requests
Completed 8000 requests
Completed 10000 requests
Completed 12000 requests
Completed 14000 requests
Completed 16000 requests
apr_poll: The timeout specified has expired (70007)
Total of 16347 requests completed

它在 16500 左右崩溃。为什么?我怎样才能知道发生了什么事。是 ruby​​ 中的 GC 还是 OS X 机器上可用网络套接字数量的问题。我有 MPB 2.5 Ghz 6G 内存。


编辑

在这里进行一些讨论并测试各种事情后,似乎将 net.inet.tcp.msl 从 15000 更改为 1000ms 使得使用 ab 测试高频 Web 服务器的问题消失了。

sudo sysctl -w net.inet.tcp.msl=1000 # this is only good for local development

请参阅参考问题以及该问题的答案。 “ab”程序在收到大量请求后冻结,为什么?

Possible Duplicate:
'ab' program freezes after lots of requests, why?

Here's a simple test server:

require 'rubygems'
require 'rack'
require 'thin'

class HelloWorld

  def call(env)
    [200, {"Content-Type" => "text/plain"}, "OK"]
  end
end

Rack::Handler::Thin.run HelloWorld.new, :Port => 9294 
#I've tried with these added too, 'rack.multithread' => true, 'rack.multiprocess' => true

Here's a test run:

$ ab -n 20000 http://0.0.0.0:9294/sdf
This is ApacheBench, Version 2.3 <$Revision: 655654 
gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 0.0.0.0 (be patient)
Completed 2000 requests
Completed 4000 requests
Completed 6000 requests
Completed 8000 requests
Completed 10000 requests
Completed 12000 requests
Completed 14000 requests
Completed 16000 requests
apr_poll: The timeout specified has expired (70007)
Total of 16347 requests completed

It breaks down at around 16500. Why? How can I find out what's going on. Is it GC in ruby or is it something with number of available network sockets on an OS X machine. I have a MPB 2.5 Ghz 6G memory.


Edit

After some discussion here and testing various things, it seems like changing net.inet.tcp.msl from 15000 to 1000ms makes the problem of testing high frequency web servers with ab go away.

sudo sysctl -w net.inet.tcp.msl=1000 # this is only good for local development

See referenced question with the answer to this problem. 'ab' program freezes after lots of requests, why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

狠疯拽 2025-01-09 23:18:11

为了清楚起见,我将在此处添加解决方案。在 os X 上使用 ab 进行高频测试的正确解决方案是将“net.inet.tcp.msl”设置从 15000ms 更改为 1000ms。这只能在开发盒上完成。

 sudo sysctl -w net.inet.tcp.msl=1000 # this is only good for local development

这个答案是在此处的评论中进行了良好的侦探工作后找到的,并且来自对一个非常相似的问题的回答,这是答案:https: //stackoverflow.com/a/6699135/155031

I'll add the solution here for claritys sake. The correct solution for managing to do high frequency tests with ab on os X is to change the 'net.inet.tcp.msl' setting from 15000ms to 1000ms. This should only be done on development boxes.

 sudo sysctl -w net.inet.tcp.msl=1000 # this is only good for local development

This answer was found after the good detective work performed in the comments here and comes from an answer to a very similar question here's the answer: https://stackoverflow.com/a/6699135/155031

栖竹 2025-01-09 23:18:11

我想我已经明白了。

当 ab 与测试服务器建立连接时,它会打开源端口(例如 50134)并与目标端口(9294)建立连接。

ab 为源端口打开的端口由 sysctl 设置 net.inet.ip.portrange.first 和 net.inet.ip.portrange.last 确定。例如,在我的机器上:

philippotter ~ $ sysctl -a | grep ip.portrange
net.inet.ip.portrange.lowfirst: 1023
net.inet.ip.portrange.lowlast: 600
net.inet.ip.portrange.first: 49152
net.inet.ip.portrange.last: 65535
net.inet.ip.portrange.hifirst: 49152
net.inet.ip.portrange.hilast: 65535

这意味着 ab 的源端口范围将在 49152 到 65535 之间,总共 16384 个。

HTTP 是 TCP 协议。当 TCP 连接关闭时,它会进入 TIME_WAIT 状态,同时等待使任何剩余的传输中的数据包到达目的地。这意味着在达到超时之前该端口不能用于任何其他目的。

因此,将所有这些放在一起,ab 很快就会用完所有可用的源端口;他们进入TIME_WAIT状态;它们不能重复使用; ab 无法创建更多连接。

如果您在 ab 挂起时杀死它,然后再次运行它,您可以看到这一点 - 它将无法创建任何连接!

I think I've got it.

When ab makes connections to your test server, it opens a source port (say, 50134) and makes a connection to the destination port (9294).

The ports that ab opens for the source port are determined by the sysctl settings net.inet.ip.portrange.first and net.inet.ip.portrange.last. For example, on my machine:

philippotter ~ $ sysctl -a | grep ip.portrange
net.inet.ip.portrange.lowfirst: 1023
net.inet.ip.portrange.lowlast: 600
net.inet.ip.portrange.first: 49152
net.inet.ip.portrange.last: 65535
net.inet.ip.portrange.hifirst: 49152
net.inet.ip.portrange.hilast: 65535

This means that ab's source ports will be in the range from 49152 to 65535, which is a total of 16384.

HTTP is a TCP protocol. When a TCP connection is closed, it goes into the TIME_WAIT state, while it waits for any remaining in-transit packets to reach their destinations. This means that the port is not usable for any other purpose until the timeout is reached.

So, putting all of this together, ab uses up all available source ports very quickly; they go into the TIME_WAIT state; they can't be reused; ab is unable to create any more connections.

You can see this if you kill ab when it hangs, and run it again -- it won't be able to create any connections!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文