2017-01-21 14 views
5

Chcę stworzyć system, który nie będzie miał pojedynczego punktu awarii. Miałem wrażenie, że routery są narzędziem do robienia tego, ale nie jestem pewien, czy działa tak, jak bym się spodziewał. Jest to punkt wejścia mojego programu:Akka pojedynczy punkt awarii

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") 
} 

I jest to kod do uruchomienia zdalnego ActorSystem (tak, router mógł wdrożyć kod TestActor do odległych węzłów):

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

I uruchomiłem to dwukrotnie, raz z testactor1 i raz z testactor2.

TestActor Kod:

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}") 
    } 
} 

I 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 
    } 
    } 
} 

Teraz problemem jest to, że gdy proces, który rozpoczął się router zostaje zabity, aktorzy, które są uruchomione kod TestActor, nie otrzymują żadnych wiadomości (wiadomości wysyłanych przez program planujący), oczekiwałbym, że router zostanie wdrożony w innym węźle źródłowym w klastrze, a aktorzy zostaną odzyskani. czy to możliwe? lub czy istnieje inny sposób wdrożenia tego przepływu i braku pojedynczego punktu awarii?

Odpowiedz

2

Myślę, że wdrażając router tylko na jednym węźle, konfigurujesz klaster master-slave, gdzie master jest z definicji pojedynczym punktem awarii.

Z tego, co rozumiem (patrząc na docs), router może być świadomy istnienia klastrów w tym sensie, że może wdrażać (w trybie puli) lub wyszukiwania (w trybie grupowym) trasy w węzłach w klastrze. Sam router nie zareaguje na niepowodzenie, odradzając się gdzie indziej w klastrze.

wierzę masz 2 opcje:

  1. skorzystać z wieloma routerami, aby sprawić, że system jest bardziej odporny na uszkodzenia. Routee mogą być współdzielone (tryb grupowy) lub nie (tryb puli) między routerami.

  2. użyć wzoru Cluster Singleton - który pozwala na konfigurację master-slave, w której master zostanie automatycznie ponownie zainicjowany w przypadku awarii. W odniesieniu do twojego przykładu, zauważ, że to zachowanie jest osiągane przez umieszczenie aktora (ClusterSingletonManager) w każdym węźle. Ten aktor ma na celu wypracowanie, czy wybrany mistrz musi być respawned i gdzie. Żadna z tych logik nie jest dostępna w przypadku routera obsługującego klastry, takiego jak ten, który ustawiłeś.

Można znaleźć przykłady wielu konfiguracji klastrów w tym Activator sample.

+0

1) powiedzmy, że mam dwa węzły działające testActor następnie proponujesz zacząć router na każdego z nich (grupa mieć dokładnie te same dwie instancje na każdym routerze). jak mam teraz korzystać z routera? Chodzi mi o to, jaki będzie cel używania go? jeśli chcę wysłać wiadomość rozgłoszeniową do rutowanych, wyślę wiadomość do jednego z węzłów zawierających router (a ten węzeł może być niedostępny) lub wyślę do wszystkich z nich, a następnie otrzymam obsługę wielu komunikatów. Czy czegoś brakuje? 2) Jeśli używam 'ClusterSingletonManager' nie znaczy to, że nie mogę uruchomić dwóch aktorów z' TestActor'? –

0

Testowałem dwa podejścia, najpierw używając twojego kodu z ClusterRouterPool Tak jak powiedziałeś, gdy proces, który rozpoczął router, został zabity, TestActor nie otrzymuje więcej wiadomości. Podczas czytania dokumentacji i badań, jeśli zmieni się application.conf:

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

tego

`auto-down-unreachable-after = off` 

TestActor utrzymania otrzymaniu wiadomości, chociaż w dzienniku pojawia się następujący komunikat (I don`t jak to zrobić, przepraszam):

[WARN] [01/30/2017 17: 20: 26.017] [mySys-akka.remote.default-remote-dispatcher-5] [akka.tcp : //[email protected]: 2554/system/endpointManager/reliable EndpointWriter-akka.tcp% 3A% 2F% 2FmySys% 40127.0.0.1% 3A2552-0] Powiązanie ze zdalnym systemem [akka.tcp: //[email protected]: 2552] nie powiodło się, adres jest teraz bramkowany dla [5000] ms. Przyczyna: [Association failed with [akka.tcp: //[email protected]: 2552]]] Przyczyna: [Połączenie odrzucone: /127.0.0.1:2552] [INFO] [01/30/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] router jest na ścieżce Aktor [akka.tcp: //[email protected]: 2552/user/testActors # -1120251475] [WARN] [01/30/2017 17: 20: 32.016] [mySys-akka.remote. default-remote-dyspozytor-5]

A w przypadku MainApp zostaje wznowiona dziennik działa normalnie bez ostrzeżenia lub błędy

MainApp Log:

[INFO] [01/30/2017 17: 23: 32.756] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Węzeł klastra [akka.tcp : //[email protected]: 2552] - Witamy z [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)] Węzeł klastra [akka.tcp: //[email protected]: 2554] - Nowe wcielenie istniejącego członka [Członek (adres = akka.tcp: //[email protected]: 2552, status = Up)] próbuje dołączyć. Istniejące zostaną usunięte z klastra, a następnie nowy członek będzie mógł dołączyć. [INFO] [01/30/2017 17: 23: 21.959] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Węzeł klastra [akka.tcp: //[email protected]:2554] - Oznaczanie nieosiągalnego węzła [akka.tcp: //[email protected]: 2552] jako [W dół] [INFO] [01/30/2017 17: 23: 22.454] [ mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Węzeł klastra [akka.tcp: //[email protected]: 2554] - Lider może ponownie wykonywać swoje obowiązki [INFO] [01/30/2017 17: 23: 22.461] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Węzeł klastra [akka.tcp: //[email protected]] - Przywódca usuwa nieosiągalny węzeł [akka.tcp: //[email protected]: 2552] [INFO] [01/30/2017 17: 23: 32.728] [mySys- akka.actor.default-dispatcher-4] [akka.cluster.Cluster (akka: // mySys)] Węzeł klastra [akka.tcp: //[email protected]: 2554] - Węzeł [akka.tcp: // [email protected]: 2552] to ŁĄCZENIE, role [] [INFO] [01/30/2017 17: 23: 33.457] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Węzeł klastra [akka.tcp: //[email protected]] - Węzeł przenosi węzeł [akka.tcp: //[email protected]: 2552] na [Up] [INFO] [01/30/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] router to na ścieżce Aktor [akka.tcp: //[email protected]: 2552/user/testActors # -630150507]

Innym sposobem jest użycie ClusterRouterGroup, ponieważ routees są dzielone pomiędzy węzłami klastra

  • Grupy - router, który wysyła wiadomości do określona ścieżka za pomocą wyboru aktora Grupy routingu mogą być współdzielone przez routery działające na różnych węzłach w klastrze. Przykładem użycia dla tego typu routera jest usługa działająca na niektórych węzłach zaplecza w klastrze i używana przez routery działające na frontowych węzłach w klastrze.
  • Basen - router, który tworzy routees jako podmioty podrzędne i wdraża je na zdalnych węzłach. Każdy router będzie miał własne instancje routingu. Na przykład, jeśli router zostanie uruchomiony na 3 węzłach w klastrze z 10 węzłami, w sumie będzie 30 tras, jeśli router jest skonfigurowany do korzystania z jednej instancji na węzeł. Trasy utworzone przez różne routery nie będą dzielone między routery. Przykładem przypadku użycia dla tego typu routera jest pojedynczy wzorzec, który koordynuje zadania i przekazuje faktyczną pracę do tras działających na innych węzłach w klastrze.

Główny 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") 
} 

należy rozpocząć TestActor w każdym węźle zdalnym

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

aktorów routee należy rozpocząć jak najwcześniej, gdy zaczyna system aktorski, ponieważ router spróbuje użyć th em, gdy status członka zmieni się na "Up".

Mam nadzieję, że to pomaga