2017-01-21 24 views
5

Я хочу создать систему, в которой не будет единой точки отказа. У меня создалось впечатление, что маршрутизаторы - это инструмент для этого, но я не уверен, что он работает так, как я ожидал. Это точка входа моей программы:Akka единственная точка отказа

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

И это код для запуска удаленного ActorSystem (так маршрутизатора может развернуть TestActor код на удаленные узлы):

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

I 'пробегает это дважды, один раз с testactor1 и один раз с testactor2.

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

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

Теперь проблема заключается в том, что, когда процесс, который начался маршрутизатор убит, актеры, выполняющиеся код TestActor, не получают никаких сообщений (сообщений, отправляемых планировщиком), я бы ожидал, что маршрутизатор будет развернут на другом семенном узле в кластере, и участники будут восстановлены. Это возможно? или есть ли другой способ реализации этого потока и не иметь единственной точки отказа?

ответ

2

Я думаю, что, развернув router только на одном узле, вы настраиваете кластер ведущего-ведомого, где мастер является единственной точкой отказа по определению.

Из того, что я понимаю (глядя на docs), маршрутизатор может быть осведомлен о кластере в том смысле, что он может развертывать (пул) или искать (групповой режим) маршруты на узлах кластера. Сам маршрутизатор не будет реагировать на отказ путем нереста в другом месте кластера.

Я считаю, что у вас есть 2 варианта:

  1. использовать несколько маршрутизаторов, чтобы сделать вас систему более отказоустойчивой. Маршрутизаторы могут быть разделены (групповой режим) или нет (режим пула) между маршрутизаторами.

  2. использовать шаблон Cluster Singleton - который позволяет создать конфигурацию ведущего-ведомого, где мастер автоматически будет повторно установлен в случае сбоя. В связи с вашим примером обратите внимание, что это поведение достигается за счет того, что в каждом узле развернут актер (ClusterSingletonManager). У этого актера есть цель разработки, если выбранный мастер должен быть обновлен и где. Ни одна из этих логических схем не используется в случае маршрутизатора, поддерживающего кластер, как тот, который вы настраиваете.

В этом Activator sample приведены примеры нескольких установок кластера.

+0

1) позволяет сказать, что у меня есть два узла под управлением testActor то предлагаю начать маршрутизатор на каждом из них (группа, чтобы иметь одни и те же два экземпляра на каждом маршрутизаторе). теперь как я буду использовать маршрутизатор? Я имею в виду, какова будет его цель? если я хочу отправить широковещательное сообщение на маршруты, я либо отправлю сообщение на один из узлов, содержащих маршрутизатор (и этот узел может быть недоступен), либо отправить их всем, а затем получить несколько сообщений. Я что-то упускаю? 2) Если я использую 'ClusterSingletonManager', это не значит, что я не могу запустить двух актеров с помощью TestActor? –

0

Я протестировал два подхода, сначала используя ваш код с ClusterRouterPool Как вы сказали, когда процесс, запускающий маршрутизатор, был убит, TestActor не получит больше сообщений. При чтении документации и тестирование, если вы изменили в application.conf:

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

для этого

`auto-down-unreachable-after = off` 

TestActor продолжать получать сообщения, хотя в журнал, появляется следующее сообщение (я Don `T знать, как поставить журнал здесь, извините):

[WARN] [01/30/2017 17: 20: 26.017] [mySys-akka.remote.default-remote-dispatcher-5] [akka.tcp : //[email protected]: 2554/система/endpointManager/надежность EndpointWriter-akka.tcp% 3A% 2F% 2FmySys% 40127.0.0.1% 3A2552-0] Ассоциация с удаленной системой [akka.tcp: //[email protected]: 2552] потерпела неудачу, адрес теперь заблокирован для [5000] Миз. Причина: [Сбой ассоциации с [akka.tcp: //mySys @12.0.0.1: 2552]] Вызвано: [Соединение отказано: /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] маршрутизатор находится на пути. Актер [akka.tcp: //[email protected]: 2552/user/testActors # -1120251475] [WARN] [01/30/2017 17: 20: 32.016] [mySys-akka.remote. по умолчанию-дистанционный диспетчер-5]

И в случае MainApp перезапуск журнала работает нормально без предупреждения или ошибок

MainApp Вход:

[INFO] [01/30/2017 17: 23: 32.756] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Cluster Node [akka.tcp : //[email protected]: 2552] - Приветствие [akka.tcp: //[email protected]: 2554]

TestActor Вход:

INFO] [01/30/2017 17: 23: 21.958] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Узел кластера [akka.tcp: //mySys @12.0.0.1: 2554] - Новое воплощение существующего участника [Участник (адрес = akka.tcp: //[email protected]: 2552, status = Up)] пытается присоединиться. Существующие будут удалены из кластера, а затем новому члену будет разрешено присоединиться. [INFO] [01/30/2017 17: 23: 21.959] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Cluster Node [akka.tcp: //[email protected]:2554] - Маркировка недостижимого узла [akka.tcp: //[email protected]: 2552] как [Вниз] [INFO] [01/30/2017 17: 23: 22.454] [ mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Cluster Node [akka.tcp: //[email protected]: 2554] - Лидер может выполнять свои обязанности снова [INFO] [01/30/2017 17: 23: 22.461] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster (akka: // mySys)] Cluster Node [akka.tcp: //[email protected]:2554] - Лидер удаляет недостижимый узел [akka.tcp: //[email protected]: 2552] [INFO] [01/30/2017 17: 23: 32.728] [mySys- akka.actor.default-dispatcher-4] [akka.cluster.Cluster (akka: // mySys)] Cluster Node [akka.tcp: //mySys @12.0.0.1: 2554] - Узел [akka.tcp: // [email protected]: 2552] - СОХРАНИТЬ, роли [] [INFO] [01/30/2017 17: 23: 33.457] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster (akka: // mySys)] Cluster Node [akka.tcp: //[email protected]:2554] - Лидер перемещает узел [akka.tcp: //[email protected]: 2552] на [Вверх] [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 is по пути Актер [akka.tcp: //[email protected]: 2552/пользователь/testActors # -630150507]

Другой подход заключается в использовании ClusterRouterGroup, потому что routees распределяются между узлами кластера

  • Group - маршрутизатор, который отправляет сообщения в указанный путь с использованием выбора актера Маршруты могут совместно использоваться маршрутизаторами, работающими на разных узлах кластера. Одним из примеров использования для этого типа маршрутизатора является служба, работающая на некоторых базовых узлах кластера и используемая маршрутизаторами, работающими на интерфейсных узлах кластера.
  • Пул - маршрутизатор, который создает маршруты как дочерние субъекты и развертывает их на удаленных узлах. Каждый маршрутизатор будет иметь свои собственные экземпляры маршрутов. Например, если вы запустите маршрутизатор на 3 узлах кластера из 10 узлов, вы получите 30 маршрутов, если маршрутизатор настроен на использование одного экземпляра на узел. Маршруты, созданные разными маршрутизаторами, не будут использоваться совместно с маршрутизаторами. Одним из примеров использования для этого типа маршрутизатора является один ведущий, который координирует задания и делегирует фактическую работу маршрутам, выполняемым на других узлах кластера.

Главная 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") 
} 

вы должны начать TestActor в каждом удаленном узле

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

The routee актеры должны быть начато как можно раньше при запуске актер системы, потому что маршрутизатор будет пытаться использовать em, как только статус участника будет изменен на «Вверх».

Я надеюсь, что это поможет вам