当我向新创建的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
。
关于如何消除一秒等待的任何想法?
答案 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