Ejabberd 网络层性能不佳
Ejabberd network layer is not performant
我知道 ejabberd 服务器是高效的并且专为高性能和容错而设计,但我不明白为什么我看到它的侦听器模块按顺序处理连接,在 Joe Armestrong 的书中我看到并行服务器是这样工作的:
{ok, Listen}=gen_tcp:listen(....),
spawn(fun() ->parallel(Listen) end).
parallel(Listen) ->
{ok, Socket}=gen_tcp:accept(Listen),
spawn(fun() ->parallel(Listen) end),
handling(Socket).
handling(Socket) ->
....
但是在名为 ejabberd_listener.erl 的 EJABBERD 侦听器中,侦听机制很简单:主管有工人 children,每个 child 代表一个模块侦听器及其侦听选项(端口, network protocole, ip,...) ,有 4 或 5 children 和所有 children 运行 两个功能之一在开始时:TCP 或 UDP,最后一个代表监听传入连接的函数,当接受连接并创建套接字时,侦听器将套接字作为参数传递给模块的启动函数,并继续接受其他连接,代码中最重要的部分是:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
%% Some of work
....
ListenSocket = listen_tcp(PortIP, Module, SockOpts, Port, IPS),
%% Some of work
....
accept(ListenSocket, Module,.... ),
%% Some of work
....
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_tcp(....) ->
Res = gen_tcp:listen(....),
%% Some of work
....
case Res of {ok, ListenSocket} ->Listensocket;
%% Some of work
....
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
accept(ListenSocket, Module,... ) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
%% Some of work
....
Module:start(....,Socket,....),
%% Some of work
....
accept(ListenSocket, Module,.... );
很明显这是一个顺序侦听器,它 运行 比并行慢,那么为什么他们不使用并行机制来提高效率和性能呢?可能是我搞砸了什么,或者这是因为它是社区版,你需要修改代码,所以有 Erlang 和 Ejabberd 经验的人可以帮助我吗?
这两种变体实际上是平行的。 ejabberd_listener
调用侦听器模块中的 start
函数,至少在 ejabberd_c2s
的情况下最终会调用 xmpp_stream_in:start
,后者 starts a new gen_server process。然后 ejabberd_listener
进程可以再次调用 gen_tcp:accept
,等待另一个传入连接。
Joe Armstrong 书中的代码片段恰恰相反:它生成一个新进程以接受更多传入连接,并在现有进程中处理当前连接。目前尚不清楚(至少对我而言)这两种方式是否必然比另一种方式更高效。
我知道 ejabberd 服务器是高效的并且专为高性能和容错而设计,但我不明白为什么我看到它的侦听器模块按顺序处理连接,在 Joe Armestrong 的书中我看到并行服务器是这样工作的:
{ok, Listen}=gen_tcp:listen(....),
spawn(fun() ->parallel(Listen) end).
parallel(Listen) ->
{ok, Socket}=gen_tcp:accept(Listen),
spawn(fun() ->parallel(Listen) end),
handling(Socket).
handling(Socket) ->
....
但是在名为 ejabberd_listener.erl 的 EJABBERD 侦听器中,侦听机制很简单:主管有工人 children,每个 child 代表一个模块侦听器及其侦听选项(端口, network protocole, ip,...) ,有 4 或 5 children 和所有 children 运行 两个功能之一在开始时:TCP 或 UDP,最后一个代表监听传入连接的函数,当接受连接并创建套接字时,侦听器将套接字作为参数传递给模块的启动函数,并继续接受其他连接,代码中最重要的部分是:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
%% Some of work
....
ListenSocket = listen_tcp(PortIP, Module, SockOpts, Port, IPS),
%% Some of work
....
accept(ListenSocket, Module,.... ),
%% Some of work
....
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_tcp(....) ->
Res = gen_tcp:listen(....),
%% Some of work
....
case Res of {ok, ListenSocket} ->Listensocket;
%% Some of work
....
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
accept(ListenSocket, Module,... ) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
%% Some of work
....
Module:start(....,Socket,....),
%% Some of work
....
accept(ListenSocket, Module,.... );
很明显这是一个顺序侦听器,它 运行 比并行慢,那么为什么他们不使用并行机制来提高效率和性能呢?可能是我搞砸了什么,或者这是因为它是社区版,你需要修改代码,所以有 Erlang 和 Ejabberd 经验的人可以帮助我吗?
这两种变体实际上是平行的。 ejabberd_listener
调用侦听器模块中的 start
函数,至少在 ejabberd_c2s
的情况下最终会调用 xmpp_stream_in:start
,后者 starts a new gen_server process。然后 ejabberd_listener
进程可以再次调用 gen_tcp:accept
,等待另一个传入连接。
Joe Armstrong 书中的代码片段恰恰相反:它生成一个新进程以接受更多传入连接,并在现有进程中处理当前连接。目前尚不清楚(至少对我而言)这两种方式是否必然比另一种方式更高效。