Hello 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}
我确信这是直截了当的,只是无法弄清楚它是什么。它是导致它的并发连接数吗?你能帮助更多地了解这个吗?
此致 彼得
答案 0 :(得分:4)
您的代码会产生多个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,
在调用inets:stop/0
之前,您需要让所有生成的请求的父级等待这些请求完成。一种方法是将父pid传递给每个生成的子节点,并且httpc:request/1
返回后,让子节点向父节点发送消息。父母将产生所有N
个孩子,然后坐在循环中等待接收来自孩子的N
完成消息,并且只有在收到所有完成消息后才会调用inets:stop/0
。
它适用于8个请求而不是9个请求的原因是由于在调用inets:stop/0
之前缺少等待的竞争条件。请求处理接受器进程的Yaws池的默认大小恰好为8.当您的代码发送8个请求时,池会快速处理它以超过您的代码对inets:stop/0
的调用,但是对于9,当一个接受者处理两个请求时,会有轻微的延迟,并且轻微的时间更改足以让您inets:stop/0
调用一个或多个客户端进程。您可以通过acceptor_pool_size
配置变量修改Yaws接受器池大小。
如果您对负载测试非常认真,可以考虑使用像tsung这样的工业级解决方案,而不是自己动手。