我知道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 侦听器中,侦听的机制很简单:一个主管有工作子级,每个子级代表一个模块侦听器,具有侦听选项(端口、网络协议、ip,...),有 4 或 5 个子级,所有子级在开始时运行以下两个函数之一:TCP 或 UDP,最后一个表示传入连接的侦听函数, 当一个连接被接受并创建一个 Socket 时,侦听器将 Socket 作为参数传递给模块的启动函数并继续接受其他连接,代码最重要的部分是:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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
,从而启动一个新的gen_server进程。 然后,ejabberd_listener
进程可以自由地再次调用gen_tcp:accept
,等待另一个传入连接。
乔·阿姆斯特朗(Joe Armstrong)书中的片段则相反:它生成一个新进程来接受进一步的传入连接,并处理现有进程中的当前连接。 目前尚不清楚(至少对我来说)任何一种方式都一定比另一种方式性能更高。