YAWS 在轻负载下以错误响应。 "Unhandled reply fr. do_recv() {error,econnaborted}"
YAWS responds with errors under light load. "Unhandled reply fr. do_recv() {error,econnaborted}"
大家好 Erlangers :)
这里只是另一位 Erlang 爱好者。我有一个非常简单的 YAWS 应用程序模块,在单个客户端访问时可以正常工作。但是,如果我尝试跨越多个客户端来模拟轻流量,这些客户端就会开始收到错误消息。知道是什么原因造成的吗?
生成客户端的代码:
-module(concurrent).
-export([measure/0, get/0]).
get() ->
Result = httpc:request("http://localhost:8080/blah"),
io:format("Result: ~p.\n", [Result]).
get_spawner(0) -> io:format("Done.\n");
get_spawner(Times) ->
spawn(concurrent, get, []),
get_spawner(Times - 1).
measure() ->
io:fwrite("Starting inets...\n"),
inets:start(),
io:fwrite("Done\n"),
io:fwrite("Creating blah...\n"),
httpc:request(put, { "http://localhost:8080/blah", [], "", "" }, [], []),
io:fwrite("Done\n"),
get_spawner(9),
io:fwrite("Stopping inets...\n"),
inets:stop(),
io:fwrite("Done\n"),
init:stop().
我观察到它对于 8 个并发客户端来说一切正常,但是当我跨越 9 个或更多客户端时,它们开始从服务器接收到以下消息:
=ERROR REPORT==== 24-Jan-2017::12:30:04 ===
** Generic server httpc_manager terminating
** Last message in was {request,
{request,undefined,<0.74.0>,0,http,
{"localhost",8080},
"/blah",[],get,
{http_request_h,undefined,"keep-alive",
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,"localhost:8080",
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,[],undefined,undefined,undefined,
undefined,"0",undefined,undefined,
undefined,undefined,undefined,undefined,[]},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,false},
"http://localhost:8080/blah",[],none,[],
1485261004189,undefined,undefined,false}}
** When Server state == {state,[],httpc_manager__handler_db,
{cookie_db,undefined,8209},
httpc_manager__session_db,httpc_manager,
{options,
{undefined,[]},
{undefined,[]},
0,2,5,120000,2,disabled,false,inet,default,
default,[]}}
** Reason for termination ==
** {'EXIT',
{shutdown,
{gen_server,call,
[httpc_handler_sup,
{start_child,
[<0.61.0>,
{request,#Ref<0.0.6.64>,<0.74.0>,0,http,
{"localhost",8080},
"/blah",[],get,
{http_request_h,undefined,"keep-alive",undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,"localhost:8080",undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,[],undefined,
undefined,undefined,undefined,"0",undefined,
undefined,undefined,undefined,undefined,
undefined,[]},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,false},
"http://localhost:8080/blah",[],none,[],
1485261004189,undefined,undefined,false},
{options,
{undefined,[]},
{undefined,[]},
0,2,5,120000,2,disabled,false,inet,default,default,
[]},
httpc_manager]},
infinity]}}}
=ERROR REPORT==== 24-Jan-2017::12:30:04 ===
Error in process <0.74.0> with exit value:
{{case_clause,
{undefined,
{error,
{'EXIT',
{shutdown,
{gen_server,call,
[httpc_handler_sup,
{start_child,
[<0.61.0>,
{request,#Ref<0.0.6.64>,<0.74.0>,0,http,
{"localhost",8080},
"/blah",[],get,
{http_request_h,undefined,"keep-alive",
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,"localhost:8080",
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,undefined,[],
undefined,undefined,undefined,
undefined,"0",undefined,undefined,
undefined,undefined,undefined,
undefined,[]},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,false},
"http://localhost:8080/blah",[],none,[],
1485261004189,undefined,undefined,false},
{options,
{undefined,[]},
{undefined,[]},
0,2,5,120000,2,disabled,false,inet,default,
default,[]},
httpc_manager]},
infinity]}}}}}},
[{httpc,handle_request,9,[{file,"httpc.erl"},{line,574}]},
{concurrent,get,0,
[{file,
"c:/Users/piotr_justyna/Documents/rets/performance_tests/concurrent.erl"},
{line,5}]}]}
在服务器端我得到这个:
=ERROR REPORT==== 24-Jan-2017::12:28:55 ===
Unhandled reply fr. do_recv() {error,econnaborted}
我确定它很简单,只是无法弄清楚它是什么。是并发连接数导致的吗?你能帮忙解释一下吗?
此致,
彼得
您的代码产生了多个 httpc:request/1
调用,但随后它立即停止了 inets
:
...
get_spawner(9),
io:fwrite("Stopping inets...\n"),
inets:stop(),
...
由于 inets
已关闭,仍在进行中的请求将过早关闭,如您在错误报告中所见:
** Reason for termination ==
** {'EXIT',
{shutdown,
{gen_server,call,
[httpc_handler_sup,
您需要让所有衍生请求的 parent 等待这些请求完成后再调用 inets:stop/0
。一种方法是将 parent pid 传递给每个生成的 child,一旦 httpc:request/1
returns,让 child 向 parent。 parent 将产生所有 N
children,然后坐在一个循环中等待接收来自 children 的 N
完成消息,并且只有在接收到所有完成消息会调用 inets:stop/0
.
它适用于 8 个请求而不适用于 9 个请求的原因是由于在调用 inets:stop/0
之前缺少等待的竞争条件。 Yaws 请求处理接受器进程池的默认大小恰好是 8。当您的代码发送 8 个请求时,池处理它的速度足以击败您的代码对 inets:stop/0
的调用,但是对于 9,会有轻微的延迟因为一个接受器处理两个请求,所以时间上的微小变化足以让您的 inets:stop/0
调用破坏一个或多个客户端进程。您可以通过 acceptor_pool_size
配置变量修改 Yaws 受体池大小。
如果您认真对待负载测试,您可以考虑使用 tsung 之类的 industrial-strength 解决方案,而不是自己动手。
大家好 Erlangers :)
这里只是另一位 Erlang 爱好者。我有一个非常简单的 YAWS 应用程序模块,在单个客户端访问时可以正常工作。但是,如果我尝试跨越多个客户端来模拟轻流量,这些客户端就会开始收到错误消息。知道是什么原因造成的吗?
生成客户端的代码:
-module(concurrent).
-export([measure/0, get/0]).
get() ->
Result = httpc:request("http://localhost:8080/blah"),
io:format("Result: ~p.\n", [Result]).
get_spawner(0) -> io:format("Done.\n");
get_spawner(Times) ->
spawn(concurrent, get, []),
get_spawner(Times - 1).
measure() ->
io:fwrite("Starting inets...\n"),
inets:start(),
io:fwrite("Done\n"),
io:fwrite("Creating blah...\n"),
httpc:request(put, { "http://localhost:8080/blah", [], "", "" }, [], []),
io:fwrite("Done\n"),
get_spawner(9),
io:fwrite("Stopping inets...\n"),
inets:stop(),
io:fwrite("Done\n"),
init:stop().
我观察到它对于 8 个并发客户端来说一切正常,但是当我跨越 9 个或更多客户端时,它们开始从服务器接收到以下消息:
=ERROR REPORT==== 24-Jan-2017::12:30:04 ===
** Generic server httpc_manager terminating
** Last message in was {request,
{request,undefined,<0.74.0>,0,http,
{"localhost",8080},
"/blah",[],get,
{http_request_h,undefined,"keep-alive",
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,"localhost:8080",
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,[],undefined,undefined,undefined,
undefined,"0",undefined,undefined,
undefined,undefined,undefined,undefined,[]},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,false},
"http://localhost:8080/blah",[],none,[],
1485261004189,undefined,undefined,false}}
** When Server state == {state,[],httpc_manager__handler_db,
{cookie_db,undefined,8209},
httpc_manager__session_db,httpc_manager,
{options,
{undefined,[]},
{undefined,[]},
0,2,5,120000,2,disabled,false,inet,default,
default,[]}}
** Reason for termination ==
** {'EXIT',
{shutdown,
{gen_server,call,
[httpc_handler_sup,
{start_child,
[<0.61.0>,
{request,#Ref<0.0.6.64>,<0.74.0>,0,http,
{"localhost",8080},
"/blah",[],get,
{http_request_h,undefined,"keep-alive",undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,"localhost:8080",undefined,undefined,
undefined,undefined,undefined,undefined,
undefined,undefined,undefined,[],undefined,
undefined,undefined,undefined,"0",undefined,
undefined,undefined,undefined,undefined,
undefined,[]},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,false},
"http://localhost:8080/blah",[],none,[],
1485261004189,undefined,undefined,false},
{options,
{undefined,[]},
{undefined,[]},
0,2,5,120000,2,disabled,false,inet,default,default,
[]},
httpc_manager]},
infinity]}}}
=ERROR REPORT==== 24-Jan-2017::12:30:04 ===
Error in process <0.74.0> with exit value:
{{case_clause,
{undefined,
{error,
{'EXIT',
{shutdown,
{gen_server,call,
[httpc_handler_sup,
{start_child,
[<0.61.0>,
{request,#Ref<0.0.6.64>,<0.74.0>,0,http,
{"localhost",8080},
"/blah",[],get,
{http_request_h,undefined,"keep-alive",
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,"localhost:8080",
undefined,undefined,undefined,
undefined,undefined,undefined,
undefined,undefined,undefined,[],
undefined,undefined,undefined,
undefined,"0",undefined,undefined,
undefined,undefined,undefined,
undefined,[]},
{[],[]},
{http_options,"HTTP/1.1",infinity,true,
{essl,[]},
undefined,false,infinity,false},
"http://localhost:8080/blah",[],none,[],
1485261004189,undefined,undefined,false},
{options,
{undefined,[]},
{undefined,[]},
0,2,5,120000,2,disabled,false,inet,default,
default,[]},
httpc_manager]},
infinity]}}}}}},
[{httpc,handle_request,9,[{file,"httpc.erl"},{line,574}]},
{concurrent,get,0,
[{file,
"c:/Users/piotr_justyna/Documents/rets/performance_tests/concurrent.erl"},
{line,5}]}]}
在服务器端我得到这个:
=ERROR REPORT==== 24-Jan-2017::12:28:55 ===
Unhandled reply fr. do_recv() {error,econnaborted}
我确定它很简单,只是无法弄清楚它是什么。是并发连接数导致的吗?你能帮忙解释一下吗?
此致, 彼得
您的代码产生了多个 httpc:request/1
调用,但随后它立即停止了 inets
:
...
get_spawner(9),
io:fwrite("Stopping inets...\n"),
inets:stop(),
...
由于 inets
已关闭,仍在进行中的请求将过早关闭,如您在错误报告中所见:
** Reason for termination ==
** {'EXIT',
{shutdown,
{gen_server,call,
[httpc_handler_sup,
您需要让所有衍生请求的 parent 等待这些请求完成后再调用 inets:stop/0
。一种方法是将 parent pid 传递给每个生成的 child,一旦 httpc:request/1
returns,让 child 向 parent。 parent 将产生所有 N
children,然后坐在一个循环中等待接收来自 children 的 N
完成消息,并且只有在接收到所有完成消息会调用 inets:stop/0
.
它适用于 8 个请求而不适用于 9 个请求的原因是由于在调用 inets:stop/0
之前缺少等待的竞争条件。 Yaws 请求处理接受器进程池的默认大小恰好是 8。当您的代码发送 8 个请求时,池处理它的速度足以击败您的代码对 inets:stop/0
的调用,但是对于 9,会有轻微的延迟因为一个接受器处理两个请求,所以时间上的微小变化足以让您的 inets:stop/0
调用破坏一个或多个客户端进程。您可以通过 acceptor_pool_size
配置变量修改 Yaws 受体池大小。
如果您认真对待负载测试,您可以考虑使用 tsung 之类的 industrial-strength 解决方案,而不是自己动手。