【问题标题】:Global Dynamic Supervisor in a cluster集群中的全局动态主管
【发布时间】:2019-03-06 15:11:42
【问题描述】:

我有一个独特的问题,我不需要在 elxir 中解决。

我需要使用动态主管在集群环境中动态启动 (n) 个子级。我正在使用 libcluster 来管理集群并使用全局进程注册表来查找动态主管 pid。这是发生的事情:

global: Name conflict terminating {:packer_supervisor, #PID<31555.1430.0>}

这是主管的代码:

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

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

感谢您的帮助。

【问题讨论】:

标签: elixir cluster-analysis


【解决方案1】:

经过一番研究,我找到了解决方案:

我现在使用https://github.com/bitwalker/swarm 来处理pid 注册。这允许跨集群设置进程,并在其中一个节点出现故障时提供切换支持。

【讨论】:

    【解决方案2】:

    您可以使用一个简单的中心节点来监控其他节点,当然是一个主管。

    这个中心节点只启动monitor,并使用数据库保存其他节点的状态和pid。

    当一个节点加入和宕机时,你可以收到它的宕机消息并进行处理(更新数据库)。

    这种方法唯一的缺点是你只能有一个中心节点,但是由于这个节点做的事情很简单,它几乎是稳定的,在我们的生产系统上运行了一年。

    【讨论】:

      【解决方案3】:

      如果您想要一个适用于全局进程注册表的相当简单的解决方案,您可以更改您的动态主管 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
      

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

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

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

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

      【讨论】:

      • 给你赏金。感谢您的回答。我最终选择了 Swarm。
      猜你喜欢
      • 2018-06-09
      • 2012-09-19
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      相关资源
      最近更新 更多