HTTP / 1.1的1秒延迟100继续ruby(美洲狮,独角兽,webrick)

时间:2016-12-20 06:49:50

标签: ruby http

当我向新创建的rails应用程序发送请求时(使用rails new),它可以快速运行:

~ 冬 time curl -v -X POST --data key=value  http://localhost:3000/ok    
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> POST /ok HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Length: 9
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 9 out of 9 bytes
< HTTP/1.1 200 OK
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< Content-Type: application/json; charset=utf-8
< ETag: W/"a29ee2b15c494311c52521766e44af56"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 99e6d922-dcd6-4e25-89a2-35fa735a401e
< X-Runtime: 0.003076
< Transfer-Encoding: chunked
< 
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
{"status":"ok"}curl -v -X POST --data key=value http://localhost:3000/ok  0.00s user 0.00s system 23% cpu 0.014 total

但是,如果我发送文件或multipart/form-data,则总是需要1秒钟(1.014 total):

~ 冬 time curl -v -X POST --form key=value  http://localhost:3000/ok    
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> POST /ok HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.51.0
> Accept: */*
> Content-Length: 143
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------8cda3c76e0dbb84a
> 
* Done waiting for 100-continue
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< Content-Type: application/json; charset=utf-8
< ETag: W/"a29ee2b15c494311c52521766e44af56"
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: 13720420-bd08-44f8-8a98-aca57d70331a
< X-Runtime: 0.002236
< Transfer-Encoding: chunked
< 
* Curl_http_done: called premature == 0
* Connection #0 to host localhost left intact
{"status":"ok"}curl -v -X POST --form key=value http://localhost:3000/ok  0.01s user 0.00s system 0% cpu 1.014 total

application_controller.rb:

class ApplicationController < ActionController::Base
  # protect_from_forgery with: :exception

  def ok
    render json: {status: 'ok'}
  end

end

routes.rb中:

Rails.application.routes.draw do
  post '/ok' => 'application#ok'
end

我在几台不同的Linux机器上测试了这一点,类似的php代码也没有这样的延迟。

另外,我试图调试puma服务器并发现它冻结在这里:

# reactor.rb, line 29
while true
  begin
    ready = IO.select sockets, nil, nil, @sleep_for # waits one second here
    < ... > 

sockets参数包含Puma::Client实例,我不知道如何将此类的对象传递给IO.select

关于如何消除一秒等待的任何想法?

2 个答案:

答案 0 :(得分:3)

我认为问题实际上是基准工具(curl),而不是Ruby应用程序。

似乎curl需要更多时间来准备和发送multipart / mime(表单)请求。

我写了一个快速的Rack应用程序来确认这个问题。将以下代码放在config.ru

require 'json'
app = proc do |env|
  req = Rack::Request.new(env)
  s = req.params.to_json
  [200, {"Content-Length": s.bytesize}, [s]]
end
run app

我使用带有8个线程的碘来运行应用程序:

$ iodine -t 8 -v

使用curl进行测试:

$ time curl -X POST - 数据键=值http://localhost:3000/ {“核心价值”} 真正的0m0.064s 用户0m0.004s sys 0m0.003s

$ time curl --form key = value http://localhost:3000/ {“核心价值”} 真正的0m1.021s 用户0m0.004s sys 0m0.004s

解析请求时存在问题。

接下来,我删除了请求解析并简单地发送回一个静态字符串(新的config.ru):

require 'json'
app = proc do |env|
  # req = Rack::Request.new(env)
  s = "GO!" # req.params.to_json
  [200, {"Content-Length": s.bytesize}, [s]]
end
run app

结果:

$ time curl --form key=value  http://localhost:3000/
GO!
real    0m1.019s
user    0m0.004s
sys 0m0.003s

$ time curl -X POST --data key=value  http://localhost:3000/
GO!
real    0m0.012s
user    0m0.004s
sys 0m0.003s

换句话说,即使Ruby不执行数据解析(未解析multipart / mime),问题仍然存在。

我继续用谷歌测试......:

$time curl -X POST --data key=value  http://google.com/
...
real    0m0.090s
user    0m0.004s
sys 0m0.004s

$ time curl --form key=value  http://google.com/
...
real    0m1.083s
user    0m0.004s
sys 0m0.004s

问题在于curl,它需要更多时间来准备和发送请求。

答案 1 :(得分:2)

这是由于cURL和100-continue timeout

简而言之,curl等待最多1秒钟让服务器在发送POST之前响应100继续:

time curl --form key=value  http://google.com/

> real 0m1.067s

Vs:

time curl --expect100-timeout 0.001 --form key=value  http://google.com/

> real 0m0.086s