集群中的全局动态Supervisor

Bot*_*ous 11 cluster-analysis elixir

我有一个独特的问题,我没有必要在elxir中解决.

我需要使用动态管理器在群集环境中动态启动(n)数量的子项.我使用libcluster来管理集群并使用全局进程注册表来查找动态管理程序pid ..以下是发生的事情:

global: Name conflict terminating {:packer_supervisor, #PID<31555.1430.0>}
Run Code Online (Sandbox Code Playgroud)

以下是主管的代码:

defmodule EcompackingCore.PackerSupervisor do
  use DynamicSupervisor
  require Logger

  def start_link() do
    DynamicSupervisor.start_link(__MODULE__, :ok, name: {:global, :packer_supervisor})
  end

  def init(:ok) do
    Logger.info("Starting Packer Supervisor")
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  def add_packer(badge_id, packer_name) do
    child_spec = {EcompackingCore.Packer, {badge_id, packer_name}}
    DynamicSupervisor.start_child(:global.whereis_name(:packer_supervisor), child_spec)
  end

  def remove_packer(packer_pid) do
    DynamicSupervisor.terminate_child(:global.whereis_name(:packer_supervisor), packer_pid)
  end

  def children do
    DynamicSupervisor.which_children(:global.whereis_name(:packer_supervisor))
  end

  def count_children do
    DynamicSupervisor.count_children(:global.whereis_name(:packer_supervisor))
  end

end
Run Code Online (Sandbox Code Playgroud)

问题似乎是主管在两个节点上启动.处理这个问题的最佳方法是什么?我真的需要主管是动态的,所以我可以有效地管理工作模块.可能是一个不同的注册表?

谢谢你的帮助.

Mil*_*ric 2

如果您想要与全局进程注册表一起使用的相当简单的解决方案,您可以更改动态主管 start_link

defmodule EcompackingCore.PackerSupervisor do
  use DynamicSupervisor
  require Logger

  def start_link() do
    case DynamicSupervisor.start_link(__MODULE__, :ok, name: {:global, :packer_supervisor}) do
      {:ok, pid} ->
        {:ok, pid}
      {:error, {:already_started, pid}} ->
        # you need this pid so on each node supervisor 
        # of this dynamic supervisor can monitor this same pid
        # so each node tracks existence of your process
        {:ok, pid}
      any -> any
    end
  end

  def init(:ok) do
    Logger.info("Starting Packer Supervisor")
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  def add_packer(badge_id, packer_name) do
    child_spec = {EcompackingCore.Packer, {badge_id, packer_name}}
    DynamicSupervisor.start_child(:global.whereis_name(:packer_supervisor), child_spec)
  end

  def remove_packer(packer_pid) do
    DynamicSupervisor.terminate_child(:global.whereis_name(:packer_supervisor), packer_pid)
  end

  def children do
    DynamicSupervisor.which_children(:global.whereis_name(:packer_supervisor))
  end

  def count_children do
    DynamicSupervisor.count_children(:global.whereis_name(:packer_supervisor))
  end
end
Run Code Online (Sandbox Code Playgroud)

对于这个解决方案,很多人会说你不应该这样做,因为在网络分裂的情况下,你最终会在集群中拥有两个或更多全局进程。但是,如果您实现一些节点监控/跟踪器,那么您甚至可以处理这个问题,这样您就知道您在集群中“看到”了多少节点。

例如,如果集群大小为 5,那么您可以创建检查规则,检查您是否看到 3 个以上节点,如果没有,那么您将在 1 秒内安排下一次启动,并尝试在全局范围内再次注册动态主管,直到检查规则返回 true(意味着您属于多数群体,并且您可以在该群体中提供一致性)。另一方面,如果您的节点是少数群体并且已经拥有全局动态管理程序,则将其关闭并安排在 1 秒内启动。

这是在整个集群中实现一致性的最简单方法,但您应该考虑一件事。这个动态主管将在单个节点上启动工作程序,我确定您不希望这样做,因此宁愿使用全局注册表和一些负载平衡算法来平衡应在本地主管中启动的进程。

  • Swarm 具有内置环和静态仲裁环算法,但使用散列在集群之间分配负载。如果您的工作人员有可以计算哈希值的 ID,那么这是一个很好的解决方案。
  • Syn是另一种选择。