首先,我必须提到我在CentOS 7上运行,调整为支持100万个连接。我测试了一个简单的C服务器和客户端,我连接了512000个客户端。我可以连接更多,但我没有使用RAM来生成更多的Linux客户端机器,因为从一台机器我可以打开65536连接; 8台机器*每个64000个连接= 512000。
我创建了一个简单的Erlang服务器,我希望使用相同的C客户端连接100万或50万个客户端。我现在遇到的问题是与记忆有关。对于每次成功gen_tcp:accept
调用,我都会生成一个进程。大约50000个开放连接在服务器上花费我3.7 GB RAM,同时使用C服务器我可以使用1.9 GB RAM打开512000连接。确实,在C服务器上我没有在接受处理之后创建一个进程,我只是在while循环中再次调用accept,但即使如此...... web上的人做了这个带有更少内存的erlang事情(ejabberd riak)< / p>
我认为我传递给erlang VM的标志应该可以解决问题。从我在文档和网络上看到的内容,这就是我所拥有的:
erl +K true +Q 64200 +P 134217727 -env ERL_MAX_PORTS 40960000 -env ERTS_MAX_PORTS 40960000 +a 16 +hms 1024 +hmbs 1024
这是服务器代码,我打开1个侦听器,通过调用start(1, 5001)
监视端口5001。
start(Num,LPort) ->
case gen_tcp:listen(LPort,[{reuseaddr, true},{backlog,9000000000}]) of
{ok, ListenSock} ->
start_servers(Num,ListenSock),
{ok, Port} = inet:port(ListenSock),
Port;
{error,Reason} ->
{error,Reason}
end.
start_servers(0,_) ->
ok;
start_servers(Num,LS) ->
spawn(?MODULE,server,[LS,0]),
start_servers(Num-1,LS).
server(LS, Nr) ->
io:format("before accept ~w~n",[Nr]),
case gen_tcp:accept(LS) of
{ok,S} ->
io:format("after accept ~w~n",[Nr]),
spawn(ex,server,[LS,Nr+1]),
proc_lib:hibernate(?MODULE, loop, [S]);
Other ->
io:format("accept returned ~w - goodbye!~n",[Other]),
ok
end.
loop(S) ->
ok = inet:setopts(S,[{active,once}]),
receive
{tcp,S, _Data} ->
Answer = 1, % Not implemented in this example
gen_tcp:send(S,Answer),
proc_lib:hibernate(?MODULE, loop, [S]);
{tcp_closed,S} ->
io:format("Socket ~w closed [~w]~n",[S,self()]),
ok
end.
答案 0 :(得分:1)
鉴于这种配置,你的光束在启动时消耗了大约2.5 GB
的内存,甚至没有加载模块。
但是,如果将最大进程数减少到合理值,例如{000}连接测试+P 60000
,则内存消耗会迅速下降。
有60 000个进程限制VM在启动时仅使用527MB
虚拟内存。
我已经尝试重现您的测试,但不幸的是,我只能在内存不足(因为客户端工作)之前在我的系统上启动30 000 netcat
。但是我只观察到VM内存消耗增加到570MB
。
所以我的建议是你的数字来自高启动内存消耗而不是大量打开的连接。即便如此,你实际上应该注意统计数据的变化以及增加的打开连接数而不是绝对值。
erl + K true + Q 64200 + P 60000 -env ERL_MAX_PORTS 40960000 -env ERTS_MAX_PORTS 40960000 + a 16 + hms 1024 + hmbs 1024
所以我用命令启动了客户端
for i in `seq 1 50000`; do nc 127.0.0.1 5001 & done