在Erlang集群中的所有节点上运行gen_server的最佳方法是什么?

aft*_*oon 11 erlang erlang-otp erlang-supervisor

我正在Erlang中构建一个监视工具.在集群上运行时,它应该在所有节点上运行一组数据收集功能,并在单个"记录器"节点上使用RRD记录该数据.

当前版本的主节点(rolf_node_sup)上运行一个主管,它试图在集群中的每个节点上运行第二个主管(rolf_service_sup).然后,每个节点上的主管应该启动并监视一系列进程,这些进程将消息发送回主节点上的gen_server(rolf_recorder).

这仅适用于本地.没有在任何远程节点上启动管理程序.我使用以下代码尝试从记录器节点加载节点上的主管:

rpc:call(Node, supervisor, start_child, [{global, rolf_node_sup}, [Services]])
Run Code Online (Sandbox Code Playgroud)

我发现有几个人建议主管真的只是为本地流程而设计的.例如

在集群中所有节点上运行监督代码的实现要求的OTP方式是什么?

  • 建议将分布式应用程序作为分布式管理器树的一种替代方案.这些不适合我的用例.它们提供节点之间的故障转移,但保持代码在一组节点上运行.
  • 模块是有趣的.但是,它提供了在当前负载最小的节点上运行作业,而不是在所有节点上运行作业.
  • 或者,我可以在主服务器上创建一组受监督的"代理"进程(每个节点一个),用于proc_lib:spawn_link在每个节点上启动主管.如果某个节点出现问题,代理进程应该死掉,然后由它的主管重新启动,然后主管应该重新启动远程进程.该从属模块可能是非常有用的在这里.
  • 或者我可能过于复杂.直接监督节点是一个坏主意,相反,也许我应该构建应用程序以更松散耦合的方式收集数据.通过在多个节点上运行应用程序来构建集群,告诉一个人是主人,留下它!

一些要求:

  • 该体系结构应该能够处理加入和离开池的节点,而无需人工干预.
  • 为了简单起见,我想建立一个单主解决方案,至少在最初阶段.
  • 在我的实现中,我更倾向于使用现有的OTP工具而不是手工代码.

knu*_*tin 5

有趣的挑战,有多种解决方案。以下只是我的建议,希望能让您更好地选择如何编写程序。

据我了解您的程序,您希望有一个主节点来启动您的应用程序。这将在集群中的节点上启动 Erlang VM。该pool模块使用该slave模块来执行此操作,这需要双向进行基于密钥的 ssh 通信。它还要求您有适当的 dns 工作。

缺点slave是如果主人死了,奴隶也会死。这是设计使然,因为它可能完美地适合原始用例,但是在您的情况下它可能很愚蠢(例如,您可能仍希望收集数据,即使主站已关闭)

对于 OTP 应用程序,每个节点可以运行相同的应用程序。在您的代码中,您可以使用配置或发现来确定集群中的节点角色。

我建议使用一些操作系统工具或 daemontools 或类似工具启动 Erlang VM。每个 VM 都将启动相同的应用程序,其中一个作为主机启动,其余作为从机启动。这有一个缺点,那就是更难“自动”在集群中出现的机器上运行软件,就像你可以用 做的那样slave,但它也更加健壮。

在每个应用程序中,您都可以根据节点的角色拥有合适的监督树。删除节点间监督和生成使系统更简单。

我还建议让所有节点都推送到主节点。这样 master 就不需要真正关心 slave 中发生了什么,它甚至可能会忽略节点关闭的事实。这也允许添加新节点而无需对主节点进行任何更改。cookie 可用作身份验证。多个母版或“记录器”也相对容易。

然而,“从”节点需要注意主节点的停机和启动,并采取适当的措施,比如存储监控数据,以便稍后在主节点恢复时发送。