Как настроить спуск в akka-кластере при наличии синглета

Я прочитал в Akka документацию, что при использовании одноэлементного кластера следует избегать автоматического отключения. Я не понимаю, как настроить настройку в этом случае. Я понимаю, что могу подписаться на события членства в кластере и планировать свою стратегию в соответствии с этими сообщениями. Тем не менее, я не понимаю, как практически это будет отличаться от автоматического списания.

Когда node каким-то образом разбивается на разделы из кластера, если используется автоматическое переключение, секционированный node будет "думать" о том, что весь кластер пропал без вести и запустит собственный кластер (с его собственным одиночным движком). Но, с другой стороны, я не могу навсегда сохранить недостижимые узлы в недостижимом состоянии, потому что кластер не достигнет конвергенции (новые узлы не смогут присоединиться), и если секционированный node сам является одиночным, новый singleton node не будет назначаться, и поэтому, согласно моему пониманию, единственное, что остается сделать, это удалить недоступные узлы после некоторого времени извлечения, что и происходит автоматически.

Что мне здесь не хватает?

Ответ 1

ознакомьтесь с приведенным ниже кодом. Я отключил функцию auto-down-unreachable-after, как сказал док. Вместо этого я реализую пользовательскую логику, которая немного отличается от обычной. Ключ к приведенному ниже коду заключается в том, что произойдет сетевой раздел, только узлы кластера, которые имеют большинство, уменьшат UnreachableMember после некоторых конфигурируемых 5s. С другой стороны, меньшинство узлов кластера будет проталкивать их 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")
  }

}