我想在我正在构建的分布式应用程序中使用erlang的OTP主管。但是我很难弄清楚这种类型的管理员如何监控在远程节点上运行的进程。与erlang的start_link函数不同,start_child没有指定生成子节点的参数。OTP监控程序可以监控远程节点上的进程吗?
OTP主管是否有可能监控远程孩子,如果不是,我该如何在erlang中实现?
我想在我正在构建的分布式应用程序中使用erlang的OTP主管。但是我很难弄清楚这种类型的管理员如何监控在远程节点上运行的进程。与erlang的start_link函数不同,start_child没有指定生成子节点的参数。OTP监控程序可以监控远程节点上的进程吗?
OTP主管是否有可能监控远程孩子,如果不是,我该如何在erlang中实现?
supervisor:start_child/2
可以跨节点使用。
你混淆的原因只是关于执行上下文的混淆(有时难以保持直接)。有三种方法涉及任何OTP产卵:
请求者的上下文是一个在其中supervisor:start_child/2
称为 - 不是监督者本身的背景。
do_some_crashable_work(Data) ->
supervisor:start_child(sooper_dooper_sup, [Data]).
这可以被定义,并从上级模块导出,可以根据一个“经理”之类的过程中内部定义:通常,你可以导出一个包装调用supervisor:spawn_child/2
功能提供监事接口"service manager/supervisor/workers" idiom,或其他。不过,在所有情况下,除主管之外的其他过程都在进行此调用。
现在再次仔细查看Erlang文档supervisor:start_child/2
(here和an R19.1 doc mirror,因为有时候erlang.org由于某种原因很难判断)。请注意,类型sup_ref()
可以是注册名称,pid()
,{global, Name}
或{Name, Node}
。当用pid()
,{global, Name}
或{Name, Node}
元组呼叫时,请求者可以在任何节点上调用任何其他节点上的监督者。尽管如此,主管并不只是随机抽出一些东西。它有一个child_spec()
这是脱离,规范告诉主管应该调用什么来启动新的过程。在监督员的上下文中,第一次进入子模块的呼叫是,并且是自定义功能。尽管我们通常将其命名为start_link/N
,但它可以做我们想要的任何东西作为启动的一部分,包括声明特定的节点以产生。所以,现在我们绕了这样的事情:
%% Usually defined in the requestor or supervisor module
do_some_crashable_work(SupNode, WorkerNode, Data) ->
supervisor:start_child({sooper_dooper_sup, SupNode}, [WorkerNode, Data]).
随着像一个孩子规格:
%% Usually in the supervisor code
SooperWorker = {sooper_worker,
{sooper_worker, start_link, []},
temporary,
brutal_kill,
worker,
[sooper_worker]},
这表明第一个电话将是sooper_worker:start_link/2
:
%% The exported start_link function in the worker module
%% Called in the context of the supervisor
start_link(Node, Data) ->
Pid = proc_lib:spawn_link(Node, ?MODULE, init, [self(), Data]).
%% The first thing the newly spawned process will execute
%% in its own context, assuming here it is going to be a gen_server.
init(Parent, Data) ->
Debug = sys:debug_options([]),
{ok, State} = initialize_some_state(Data)
gen_server:enter_loop(Parent, Debug, State).
你可能想知道那些与proc_lib
有关的东西是什么。事实证明,虽然从多节点系统内的任何地方调用一个产卵器以在多节点系统内的任何其他地方发起产卵是可能的,但它并不是一种非常有用的做生意的方式,所以gen_*
行为,甚至proc_lib:start_link/N
没有声明生成新进程的节点的方法。
理想情况下,您需要的是知道如何初始化自身并在群集运行后加入群集的节点。无论您的系统提供的任何服务通常在群集中的其他节点上都得到最佳复制,然后您只需编写一个选择节点的方法,即可完全启动启动业务,因为它现在是节点本地每一个案例。在这种情况下,无论您的普通经理/主管/员工代码如何都不需要更改 - 只会发生,并且请求者的PID恰好位于另一个节点上并不重要,即使该PID是地址必须返回结果。
换句话说,我们真的不希望产卵上的任意节点的工人,我们真正想要做的是加紧向更高层次和要求,一些工作由另一节点得到完成并不在乎关于如何发生。请记住,要基于{M,F,A}
调用生成特定函数,您调用的节点必须有权访问目标模块和函数 - 如果它已经有代码副本,为什么它不是调用节点的副本?
希望这个答案解释更多比它困惑。
我认为推荐的方法是在每个节点上都有一个管理员。 – Dogbert
@Dogbert确实。实际上,不仅仅是一个主管,而且通常是分配任何系统的完整副本,以便工作请求可以跨节点,而不需要对代码进行任何重大更改。 – zxq9