Ответ 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")
}
}