You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Elixir中如何监听cluster内node加入/离开?含process消息接收及原因查询

处理Elixir集群节点加入/离开的通知机制

嘿,针对你在Elixir集群开发中遇到的两个需求——获取节点加入/离开的通知,以及让进程接收对应消息并获知节点离开原因——我刚好有不少实用的方案可以分享,都是基于Erlang/OTP原生机制和Elixir的友好封装:

一、原生节点监控:用Node.monitor/2快速实现

Elixir的Node模块封装了Erlang底层的:net_kernel监控能力,这是最直接的方案。你可以在任意进程(比如GenServer、普通工作进程甚至IEx会话里)开启节点监控,之后该进程就能收到节点变动的消息。

1. 开启监控并请求离开原因

要获取节点离开的原因,关键是开启监控时带上对应的选项。比如在你的进程初始化时调用:

# 开启所有类型节点的监控,同时请求获取离开原因
Node.monitor(true, [node_type: :all, receive_timeout: 5000])

或者直接用Erlang的底层调用(效果一致):

:net_kernel.monitor_nodes(true, [:nodedown_reason])

这里的:nodedown_reason选项就是让你能拿到节点离开原因的核心配置。

2. 处理节点变动的消息

开启监控后,你的进程会收到两种核心消息:

  • {:nodeup, node()}:当新节点成功加入集群时触发
  • {:nodedown, node(), reason}:节点离开时触发,reason就是具体原因(比如:normal正常退出、:shutdown被主动关闭、:connection_closed网络断开、:noconnection节点崩溃等)

给你写个GenServer的实战例子,直接就能用:

defmodule ClusterNodeMonitor do
  use GenServer

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  end

  @impl true
  def init(_) do
    # 启动节点监控,同时请求离开原因
    Node.monitor(true, [node_type: :all, receive_timeout: 5000])
    {:ok, nil}
  end

  @impl true
  def handle_info({:nodeup, node}, state) do
    IO.puts("🎉 节点 #{inspect(node)} 已成功加入集群!")
    # 这里可以加你的业务逻辑,比如通知其他服务、更新节点列表等
    {:noreply, state}
  end

  @impl true
  def handle_info({:nodedown, node, reason}, state) do
    IO.puts("😢 节点 #{inspect(node)} 已离开集群,原因:#{inspect(reason)}")
    # 比如触发故障转移、清理该节点的资源等
    {:noreply, state}
  end
end

二、进阶方案:用libcluster做集群管理+通知

如果你的项目需要更复杂的集群节点发现(比如基于DNS、K8s、EC2的自动发现),官方推荐的libcluster库不仅能帮你搞定节点自动组网,还提供了节点变动的回调机制,不用自己手动处理消息。

只需要在config.exs里配置拓扑时,加上:on_node_add和:on_node_remove回调:

config :libcluster,
  topologies: [
    default: [
      strategy: Cluster.Strategy.Epmd, # 用Epmd做节点发现,适合本地测试
      config: [hosts: [:"node1@localhost", :"node2@localhost"]],
      on_node_add: fn node -> 
        IO.puts("新节点 #{inspect(node)} 加入,开始同步数据...")
        # 这里写你的业务逻辑
      end,
      on_node_remove: fn node, reason -> 
        IO.puts("节点 #{inspect(node)} 离开,原因:#{inspect(reason)},开始清理资源...")
      end
    ]
  ]

当然,用这个库的话需要先在mix.exs里添加依赖哦。

几个关键提醒

  • 只有开启了监控的进程才会收到节点变动消息,所以如果多个进程需要通知,可以让它们各自开启监控,或者做一个中心监控进程来转发消息给其他服务。
  • 节点离开的原因是Erlang分布式机制提供的,不同场景下的reason会不一样,比如节点主动退出是:normal,崩溃的话可能是:noconnection,可以根据这些原因做不同的业务处理。
  • 前提是你的集群节点之间已经正确建立了连接(比如用Node.connect/1手动连接,或者通过libcluster自动发现),不然监控是不会生效的。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:19:43