2017-01-21 1 views
5

Je veux créer un système qui n'aura pas un seul point de défaillance. J'avais l'impression que les routeurs sont l'outil pour le faire, mais je ne suis pas sûr que cela fonctionne comme je m'y attendais. C'est le point d'entrée de mon programme:Akka point de défaillance unique

object Main extends App{ 
    val system = ActorSystem("mySys", ConfigFactory.load("application")) 
    val router = system.actorOf(
    ClusterRouterPool(RoundRobinPool(0), ClusterRouterPoolSettings(
     totalInstances = 2, maxInstancesPerNode = 1, 
     allowLocalRoutees = false, useRole = Some("testActor"))).props(Props[TestActor]), 
    name = "testActors") 
} 

Et ceci est le code pour l'exécution de la ActorSystem à distance (de sorte que le routeur peut déployer le code TestActor aux nœuds distants):

object TestActor extends App{ 
    val system = ActorSystem("mySys", ConfigFactory.load("application").getConfig("testactor1")) 
    case object PrintRouterPath 
} 

I Je cours cela deux fois, une fois avec testactor1 et une fois avec testactor2.

Code TestActor:

class TestActor extends Actor with ActorLogging{ 
    implicit val ExecutionContext = context.dispatcher 
    context.system.scheduler.schedule(10000 milliseconds, 30000 milliseconds,self, PrintRouterPath) 

    override def receive: Receive = { 
    case PrintRouterPath => 
    log.info(s"router is on path ${context.parent}") 
    } 
} 

Et application.conf

akka{ 
actor { 
    provider = "akka.cluster.ClusterActorRefProvider" 
} 
remote { 
    log-remote-lifecycle-events = off 
    netty.tcp { 
    hostname = "127.0.0.1" 
    port = 2552 
    } 
} 
cluster { 
    seed-nodes = [ 
    "akka.tcp://[email protected]:2552" 
    "akka.tcp://[email protected]:2553" 
    "akka.tcp://[email protected]:2554"] 
    auto-down-unreachable-after = 20s 
    } 
} 
testactor1{ 
    akka{ 
    actor { 
     provider = "akka.cluster.ClusterActorRefProvider" 
    } 
    remote { 
     log-remote-lifecycle-events = off 
     netty.tcp { 
     hostname = "127.0.0.1" 
     port = 2554 
     } 
    } 
    cluster { 
    roles.1 = "testActor" 
     seed-nodes = [ 
     "akka.tcp://[email protected]:2552" 
     "akka.tcp://[email protected]:2553" 
     "akka.tcp://[email protected]:2554"] 
     auto-down-unreachable-after = 20s 
    } 
    } 
} 
testactor2{ 
    akka{ 
    actor { 
     provider = "akka.cluster.ClusterActorRefProvider" 
    } 
    remote { 
     log-remote-lifecycle-events = off 
     netty.tcp { 
     hostname = "127.0.0.1" 
     port = 2553 
     } 
    } 
    cluster { 
    roles.1 = "testActor" 
     seed-nodes = [ 
     "akka.tcp://[email protected]:2552" 
     "akka.tcp://[email protected]:2553" 
     "akka.tcp://[email protected]:2554"] 
     auto-down-unreachable-after = 20s 
    } 
    } 
} 

Maintenant, le problème est que lorsque le processus qui a commencé le routeur est tué, les acteurs qui exécutent le code de TestActor, ne recevant aucun message (les messages que le planificateur envoie), je m'attendrais à ce que le routeur soit déployé sur un autre noeud de départ dans le cluster et les acteurs seront récupérés. Est-ce possible? ou existe-t-il un autre moyen de mettre en œuvre ce flux et de ne pas avoir un seul point de défaillance?

Répondre

2

Je pense que, en déployant le router sur un seul nœud, vous configurez un cluster maître-esclave, où le maître est un point de défaillance unique par définition. D'après ce que je comprends (en regardant le docs), un routeur peut être compatible avec les clusters en ce sens qu'il peut déployer (en mode pool) ou rechercher (en mode groupe) des routes sur des nœuds dans le cluster. Le routeur lui-même ne réagira pas à l'échec en apparaissant ailleurs dans le cluster.

Je crois que vous avez 2 options:

  1. faire usage de plusieurs routeurs pour rendre votre système plus tolérant aux pannes. Les routes peuvent être partagées (mode groupe) ou non (mode pool) entre les routeurs.

  2. utiliser le modèle Cluster Singleton - qui permet une configuration maître-esclave où le maître sera automatiquement ré-engendré en cas de défaillance. En relation avec votre exemple, notez que ce comportement est obtenu en ayant un acteur (ClusterSingletonManager) déployé dans chaque nœud. Cet acteur a pour but de travailler si le maître choisi doit être réinséré et où. Aucune de cette logique n'est en place dans le cas d'un routeur compatible avec les clusters comme celui que vous configurez.

Vous trouverez des exemples de plusieurs configurations de cluster dans cette zone Activator sample.

+0

1) permet de dire que j'ai deux noeuds en cours d'exécution testActor vous suggérez pour démarrer le routeur sur chacun d'entre eux (groupe d'avoir exactement les mêmes deux cas sur chaque routeur). maintenant comment vais-je utiliser le routeur? Je veux dire quel sera le but de l'utiliser? Si je veux envoyer un message de diffusion aux routes, je vais soit envoyer un message à l'un des noeuds contenant le routeur (et ce noeud peut être indisponible) ou les envoyer à tous et ensuite recevoir plusieurs messages. Est-ce que je manque quelque chose? 2) Si j'utilise 'ClusterSingletonManager', cela ne veut-il pas dire que je ne peux pas démarrer deux acteurs avec' TestActor'? –

0

J'ai testé deux approches, en utilisant d'abord votre code avec ClusterRouterPool Comme vous l'avez dit lorsque le processus qui a démarré le routeur est tué, TestActor ne reçoit plus de messages. En lisant la documentation et les tests, si vous changez de application.conf:

`auto-down-unreachable-after = 20s` 

pour cette

`auto-down-unreachable-after = off` 

le TestActor continuer à recevoir les messages, bien que dans le journal le message suivant apparaît (i n ` savoir comment mettre le journal ici, désolé):

[AVERTISSEMENT] [30/01/2017 17: 20: 26.017] [mySys-akka.remote.default-remote-dispatcher-5] [akka.tcp : //[email protected]: 2554/system/endpointManager/fiable EndpointWriter-akka.tcp% 3A% 2F% 2FmySys% 40127.0.0.1% 3A2552-0] L'association avec le système distant [akka.tcp: //[email protected]: 2552] a échoué, l'adresse est maintenant bloquée pour [5000] Mme. Raison: [L'association a échoué avec [akka.tcp: //[email protected]: 2552]] Causée par: [Connexion refusée: /127.0.0.1:2552] [INFO] [30/01/2017 17:20: 29.860] [mySys-akka.actor.default-dispatcher-4] [akka.tcp: //[email protected]: 2554/remote/akka.tcp/[email protected]: 2552/user/testActors/c1] le routeur est sur le chemin Acteur [akka.tcp: //[email protected]: 2552/utilisateur/testActeurs # -1120251475] [WARN] [30/01/2017 17: 20: 32.016] [mySys-akka.remote. default-distance-répartiteur-5]

et dans le cas du MainApp redémarre le journal fonctionne normalement sans avertissement ou erreurs

MainApp log:

[INFO] [30/01/2017 17: 23: 32.756] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Nœud de cluster [akka.tcp : //[email protected]: 2552] - Mot de bienvenue [akka.tcp: //[email protected]: 2554]

TestActor Log:

INFO] [30/01/2017 17: 23: 21.958] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Nœud de cluster [akka.tcp: //[email protected]: 2554] - Nouvelle incarnation du membre existant [Member (adresse = akka.tcp: //[email protected]: 2552, status = Up)] essaie de se joindre. Les éléments existants seront supprimés du cluster et le nouveau membre sera autorisé à rejoindre. [INFO] [30/01/2017 17: 23: 21.959] [mySys-akka.acteur.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Noeud de cluster [akka.tcp: //[email protected]:2554] - Marquage du noeud inaccessible [akka.tcp: //[email protected]: 2552] comme [Down] [INFO] [30/01/2017 17: 23: 22.454] [ mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Nœud de cluster [akka.tcp: //[email protected]: 2554] - Leader peut à nouveau effectuer ses tâches [INFO] [30/01/2017 17: 23: 22.461] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Nœud de cluster [akka.tcp: //[email protected]:2554] - Le gestionnaire supprime le noeud inaccessible [akka.tcp: //[email protected]: 2552] [INFO] [30/01/2017 17: 23: 32.728] [mySys- akka.actor.default-dispatcher-4] [akka.cluster.Cluster (akka: // mySys)] Nœud de cluster [akka.tcp: //[email protected]: 2554] - Nœud [akka.tcp: // [email protected]: 2552] est JOINING, rôles [] [INFO] [30/01/2017 17: 23: 33.457] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Noeud de cluster [akka.tcp: //[email protected]:2554] - Le leader déplace le nœud [akka.tcp: //[email protected]: 2552] à [Up] [INFO] [30/01/2017 17: 23: 37.925] [mySys-akka.actor.default-dispatcher-19] [akka.tcp: //[email protected]: 2554/remote/akka.tcp/[email protected]: 2552/user/testActors/c1] routeur est sur le chemin Acteur [akka.tcp: //[email protected]: 2552/user/testActors # -630150507]

L'autre approche consiste à utiliser ClusterRouterGroup, parce que les routées sont partagés entre les nœuds du cluster

  • Group - routeur qui envoie des messages au chemin spécifié à l'aide de la sélection d'acteur Les routages peuvent être partagés entre les routeurs exécutés sur différents nœuds du cluster. Un exemple de cas d'utilisation pour ce type de routeur est un service s'exécutant sur certains nœuds principaux du cluster et utilisé par les routeurs s'exécutant sur les nœuds frontaux du cluster.
  • Pool - routeur qui crée des routines en tant qu'acteurs enfants et les déploie sur des nœuds distants. Chaque routeur aura ses propres instances routee. Par exemple, si vous démarrez un routeur sur 3 nœuds dans un cluster à 10 nœuds, vous disposerez de 30 routes au total si le routeur est configuré pour utiliser une instance par nœud. Les routes créées par les différents routeurs ne seront pas partagées entre les routeurs. Un exemple de cas d'utilisation pour ce type de routeur est un seul maître qui coordonne les travaux et délègue le travail réel aux routages exécutés sur d'autres nœuds du cluster.

Le principal App

object Main extends App { 

    val system = ActorSystem("mySys", ConfigFactory.load("application.conf")) 
    val routerGroup = system.actorOf(
ClusterRouterGroup(RoundRobinGroup(Nil), ClusterRouterGroupSettings(
    totalInstances = 2, routeesPaths = List("/user/testActor"), 
    allowLocalRoutees = false, useRole = Some("testActor"))).props(), 
name = "testActors") 
} 

vous devez démarrer le TestActor dans chaque nœud distant

object TestActor extends App{ 
    val system = ActorSystem("mySys", ConfigFactory.load("application").getConfig("testactor1")) 
    system.actorOf(Props[TestActor],"testActor") 
    case object PrintRouterPath 
} 

http://doc.akka.io/docs/akka/2.4/scala/cluster-usage.html#Router_with_Group_of_Routees

Les acteurs de la routée devrait débuter le plus tôt possible lors du démarrage le système d'acteur, parce que le routeur va essayer d'utiliser le em dès que le statut du membre est changé en 'Up'.

J'espère que cela vous aide