OTP 主管可以监控远程节点上的进程吗?

Posted

技术标签:

【中文标题】OTP 主管可以监控远程节点上的进程吗?【英文标题】:Can an OTP supervisor monitor a process on a remote node? 【发布时间】:2017-04-09 01:39:05 【问题描述】:

我想在我正在构建的分布式应用程序中使用 erlang 的 OTP 主管。但是我无法弄清楚这种主管如何监控远程节点上运行的进程。与 erlang 的 start_link 函数不同,start_child 没有用于指定子节点将在其上生成的参数。

OTP 主管是否可以监控远程孩子,如果不能,我如何在 erlang 中实现这一点?

【问题讨论】:

我认为推荐的方法是在每个节点上都有一个主管。 @Dogbert 确实如此。实际上,不仅仅是主管,而且通常是正在分发的任何系统的完整副本,因此工作请求可以跨节点而不需要对代码进行任何重大更改。 【参考方案1】:

supervisor:start_child/2可以跨节点使用。

您感到困惑的原因只是对执行上下文的混淆(诚然,有时很难保持直截了当)。任何 OTP 生成都涉及三个进程:

请求者 主管 衍生进程

请求者的上下文是调用supervisor:start_child/2 的上下文——不是主管本身的上下文。您通常会通过导出一个包装对supervisor:spawn_child/2 的调用的函数来提供主管接口:

do_some_crashable_work(Data) ->
    supervisor:start_child(sooper_dooper_sup, [Data]).

这可以从主管模块定义和导出,根据"service manager/supervisor/workers" idiom 在“管理器”类型的进程内部定义,或其他。但是,在所有情况下,除了主管之外的某个进程正在发出此调用。

现在再次仔细查看 supervisor:start_child/2 的 Erlang 文档(here 和 an R19.1 doc mirror,因为有时 erlang.org 出于某种原因遇到困难)。请注意,sup_ref() 类型可以是注册名称、pid()global, NameName, Node。当使用pid()global, NameName, 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 调用生成特定函数,您正在调用的节点必须能够访问目标模块和函数——如果它已经有代码的副本,为什么它不是调用的副本节点?

希望这个答案能解释的比混淆更多。

【讨论】:

以上是关于OTP 主管可以监控远程节点上的进程吗?的主要内容,如果未能解决你的问题,请参考以下文章

JVM探秘:VisualVM监控远程Java进程

向日葵远程苹果手机需要对方同意吗

Erlang/OTP 消息可靠吗?消息可以复制吗?

Redhat+Weblogic 远程Jconsole监控java程序运行

如何分发 Erlang 进程(主管行为)?

远程监控的原理和实现如何用c语言实现