【问题标题】:How to configure downing in akka cluster when a singleton is present存在单例时如何在akka集群中配置停机
【发布时间】:2015-08-15 00:16:35
【问题描述】:

我在 Akka 的 documentation 中读到,在使用集群单例时,应避免使用自动停机。 我不明白在这种情况下应该如何配置downing。 我了解我可以订阅集群成员活动并根据这些消息计划我的策略。但是,我不明白它与自动停机有何不同。

当一个节点以某种方式从集群中分区时,如果使用自动关闭,分区节点将“认为”整个集群丢失并启动自己的集群(具有自己的单例)。 但是,另一方面,我不能将无法访问的节点永远保持在无法访问的状态,因为集群不会达到收敛(新节点将无法加入),并且如果分区节点是单例本身,那么一个新的单例节点不会被分配,因此,根据我的理解,唯一要做的就是在一段时间后删除无法访问的节点,这正是自动关闭所做的。

我错过了什么?

【问题讨论】:

  • 我和你有同样的问题。看来我们没有办法阻止2个集群分区启动自己的Cluster Singleton

标签: singleton akka akka-cluster


【解决方案1】:

查看以下代码。正如文档所说,我已经关闭了auto-down-unreachable-after 功能。相反,我实现了一个与正常情况有点不同的自定义逻辑。下面代码的关键是如果发生网络分区,只有拥有多数的集群节点会在经过一些可配置的 5s 后删除UnreachableMember。另一方面,集群中的少数节点会踩到它们的UnreachableMember(即unreachable的多数组,不会将它们取下来形成孤岛。多数数的想法是从MongoDB借来的我认为这在计算机科学领域并不新鲜。

class ClusterListener extends Actor with ActorLogging {

  val cluster = Cluster(context.system)
  var unreachableMember: Set[Member] = Set()

  // subscribe to cluster changes, re-subscribe when restart 
  override def preStart(): Unit = {
    //#subscribe
    cluster.subscribe(self, initialStateMode = InitialStateAsEvents, classOf[UnreachableMember], classOf[ReachableMember])
    //#subscribe
  }
  override def postStop(): Unit = cluster.unsubscribe(self)

  def receive = {
    case UnreachableMember(member) =>
      log.info("Member detected as unreachable: {}", member)
      val state = cluster.state
      if (isMajority(state.members.size, state.unreachable.size)) {
        scheduletakeDown(member)
      }
    case ReachableMember(member) =>
      unreachableMember = unreachableMember - member
    case _: MemberEvent => // ignore
    case "die" =>
      unreachableMember.foreach { member =>
        cluster.down(member.address)
      }
  }

  // find out majority number of the group
  private def majority(n: Int): Int = (n+1)/2 + (n+1)%2

  private def isMajority(total: Int, dead: Int): Boolean = {
    require(total > 0)
    require(dead >= 0)
    (total - dead) >= majority(total)
  }

  private def scheduletakeDown(member: Member) = {
    implicit val dispatcher = context.system.dispatcher
    unreachableMember = unreachableMember + member
    // make 5s config able!!!
    context.system.scheduler.scheduleOnce(5 seconds, self, "die")
  }

}

【讨论】:

  • 感谢您的评论,但我有些不明白。当分区(少数)节点恢复为多数时,假设网络/gc 问题已解决,除非少数节点重新启动其参与者系统(以重新生成新令牌),否则它们是否能够再次连接到多数?因为据我所知,如果从集群中删除了一个节点,它就不能返回相同的令牌。
  • 你好,我知道这是旧的。但对于任何寻找答案的人。被大多数人标记为关闭的分区节点必须明确地重新启动才能再次加入集群。 doc.akka.io/docs/akka/2.4.2/scala/…
  • 我已经在 Akka 2.4.3 上对此进行了测试,并确认它可以正常工作。我有两台机器,我在机器 A 上运行大部分节点,在机器 B 上运行少数节点。我切断 A 和 B 之间的连接以模拟分区。机器 A 节点对少数(机器 B 节点)发出删除,少数节点能够意识到他们实际上是少数。请注意,少数节点不会自行终止并保持运行。需要额外的逻辑来关闭它们。搜索“akka cluster split brain and reconnect”了解更多信息。感谢分享@mingchuno
  • 出于好奇,您是否确认不需要在集群的所有机器上启动这样的actor?我想如果它在与有单例实例的节点相同的节点上运行就足够了,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多