【问题标题】:Akka Cluster manual joinAkka Cluster 手动加入
【发布时间】:2017-06-06 08:14:51
【问题描述】:

我正在尝试寻找解决以下限制的方法:从头开始启动 Akka 集群时,必须确保启动第一个种子节点。这对我来说是个问题,因为如果我有紧急情况要从头开始重新启动我的所有系统,谁知道一切所依赖的一台机器是否会正常运行?而且我可能没有时间花时间更改系统配置。因此,我尝试手动创建集群,而不依赖于静态种子节点列表。

现在我很容易让所有 Akka 系统在某处注册自己(例如,网络文件系统,通过定期触摸文件)。因此在启动新系统时可以

  1. 查找所有假定处于活动状态的系统的列表(即最近谁接触过文件系统)。
  2. 一个。如果没有,则新系统会自行加入,即单独启动集群。湾。否则,它会尝试使用所有其他假定活着的系统作为种子,使用 Cluster(system).joinSeedNodes 加入集群。
  3. 如果 2。没有在合理的时间内成功,新系统会再次尝试,从 1 开始。(再次查找所谓的活跃系统列表,因为它可能在此期间发生了变化;特别是所有其他系统可能已经死亡,我们会最终落入 2.a.)。

我不确定如何实现 3.:我如何知道加入是成功还是失败? (需要订阅集群事件?)如果再次调用Cluster(system).joinSeedNodes 失败,是否有可能?官方文档在这一点上不是很明确,我不是 100% 如何在我的情况下解释以下内容(我可以做几次尝试,使用不同的种子吗?):

一个actor系统只能加入一个集群一次。额外的尝试将 被忽略。成功加入后,必须重新启动才能 能够加入另一个集群或再次加入同一个集群。

最后,让我准确地说,我正在构建一个小型集群(目前只有 10 个系统,它不会变得很大)并且必须不时从头开始重新启动(我不能假设集群将永远活着)。

谢谢

【问题讨论】:

    标签: akka akka-cluster


    【解决方案1】:

    我正在回答我自己的问题,让人们知道我最终是如何解决我的问题的。 Michal Borowiecki 的回答提到了 ConstructR 项目,我在他们的代码上构建了我的答案。

    我如何知道加入是成功还是失败?发出Cluster(system).joinSeedNodes后我订阅集群事件并开始超时:

    private case object JoinTimeout
    ...
    Cluster(context.system).subscribe(self, InitialStateAsEvents, classOf[MemberUp], classOf[MemberLeft])
    system.scheduler.scheduleOnce(15.seconds, self, JoinTimeout)
    

    receive 是:

    val address = Cluster(system).selfAddress
    ...
    case MemberUp(member) if member.address == address =>
      // Hooray, I joined the cluster!
    case JoinTimeout =>
      // Oops, couldn't join
      system.terminate()
    

    如果再次呼叫Cluster(system).joinSeedNodes 失败,是否有可能?也许,也许没有。但实际上,如果加入没有成功,我只是简单地终止参与者系统并重新启动它以再次尝试(所以这是参与者系统级别的“让它崩溃”模式)。

    【讨论】:

      【解决方案2】:

      您不需要种子节点。如果您希望集群自动启动,则需要种子节点。

      您可以启动您的个人应用程序,然后让它们随时“手动”加入集群。例如,如果你启用了 http,你可以使用the akka-management library(或者自己实现它的一个子集,它们都是基本的集群库函数,只是很好地包装了)。

      我强烈反对触摸方法。你如何同步节点之间的触摸读/写?如果有人读取瞬态状态(而其他人正在编写它)怎么办?

      我会说要么完全自动(具有多个种子节点),要么完全“手动”并让另一个系统负责管理节点的集群化。我的意思是您单独启动它们,并且它们仅在外部主管命令时才加入集群(对管理裂脑也很有帮助)。

      【讨论】:

      • (通过触摸我想到的文件系统触摸一个零大小的文件,其名称是参与者系统的地址,可能已编码:它是一个不需要同步读/写的原子操作。)我认为我正在寻找的是一个全自动解决方案,它使用一个种子节点列表,它不是静态的(由于第一个节点在从头开始时必须存活的限制)而是从留下的信息动态构建的,例如在文件系统上。
      【解决方案3】:

      我们已经开始使用 Constructr 扩展而不是种子节点的静态列表:

      https://github.com/hseeberger/constructr

      这没有静态配置的第一个种子节点必须在完全重启集群后启动的限制。

      相反,它依赖于高度可用的查找服务。 Constructr 原生支持 etcd,并且有(至少)zookeeper 和 consul 的扩展可用。由于我们已经有一个用于 kafka 的 zookeeper 集群,所以我们选择了 zookeeper:

      https://github.com/typesafehub/constructr-zookeeper

      【讨论】:

      • 非常感谢您的小费!我浏览了文档。如果我理解正确:zookeeper 有一个静态节点列表,但没有一个具有特殊作用。因此,当从头开始时,我们只需要有足够的可用节点,并且 zookeeper 会设法从它们中形成一个仲裁(Akka 无法在本机上做到这一点),可以通过 ConstructR 在其上构建 Akka 集群。对于我的用例来说,它看起来仍然有点复杂,但至少涵盖了它,所以我会尝试一下。
      • 我查看了 ConstructrMachine.scala 中的代码:实际上它确实实现了我正在寻找的算法,只是它没有实现我的第 3 步:ConstructR 发出一个集群(系统) .joinSeedNodes 仅一次,如果此调用失败,则加入过程中止。至少它能够确定加入是否成功。最后,我正在考虑提供我自己的“ConstructR 插件”,即由网络文件系统支持的协调实现。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-20
      相关资源
      最近更新 更多