Я использую функциональные возможности кластера Akka.NET (1.0.5) для реализации службы, состоящей из главного узла, который получает запросы по HTTP и распределяет работу между рабочими узлами, присоединившимися к кластеру.
Идея состоит в том, чтобы иметь возможность легко выполнить следующее:
добавлять рабочие узлы в кластер при высоком спросе (проверьте)
иметь возможность перезагрузить мастер-узел или перевести его в автономный режим (техническое обслуживание/неправильное поведение/что угодно) и повторно подключить рабочих, когда он станет доступным (проверьте)
обновить/перезагрузить плохо работающий рабочий процесс и повторно подключить его к главному узлу (сбой!)
Первый пункт работает, как и следовало ожидать: новый экземпляр (рабочая роль облачной службы Azure) запускается и присоединяется к главному, который также является начальным узлом.
Во-вторых, у всех рабочих узлов есть актор, который прослушивает сплетни кластера и определяет, умер ли главный узел. В этом случае система актора рабочего узла будет перезагружена.
Последний пункт, где я застрял. Главный узел также прислушивается к сплетням кластера, чтобы определить, когда рабочий процесс стал недоступен (ClusterEvent.UnreachableMember
) или закрывается (статус выхода), и решает, следует ли его отключить. Согласно тому, что я понял из документации, единственный способ вернуть «новую» версию того же узла в кластер — это сначала отключить старую версию.
К сожалению, похоже, этого не происходит. В тестовом сценарии, который я запускал для локального воспроизведения проблемы в эмуляторе вычислений, были следующие шаги:
Запустите главный узел (порт 8090)
Запустите рабочий узел (порт 9090)
Поработай немного
Внезапно убить рабочий узел
Запустите резервную копию рабочего узла
Ниже приведены соответствующие фрагменты из журналов, которые я собрал для обоих узлов во время этого теста:
Мастер:
Рабочий становится недоступным:
[WARNING][07/12/2015 20:39:35][Thread 0023][[akka://InventoryService/system/cluster/core/daemon]] Cluster Node [akka.tcp://[email protected]:8090] - Marking node(s) as UNREACHABLE [Member(address = akka.tcp://[email protected]:9090, status = Up]
Главный узел вызывает Cluster.Leave()
и Cluster.Down()
по адресу рабочего:
[DEBUG][07/12/2015 20:39:35][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.ClusterUserAction+Leave
[INFO][07/12/2015 20:39:35][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] Marked address [akka.tcp://[email protected]:9090] as Leaving]
[DEBUG][07/12/2015 20:39:35][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.ClusterUserAction+Down
[INFO][07/12/2015 20:39:35][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] Marking unreachable node [akka.tcp://[email protected]:9090] as Down
[DEBUG][07/12/2015 20:39:35][Thread 0020][[akka://InventoryService/system/cluster/core/daemon/heartbeatSender]] Cluster Node [akka.tcp://[email protected]:8090] - Heartbeat to [akka.tcp://[email protected]:9090]
[INFO][07/12/2015 20:39:36][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] Leader is removing unreachable node [akka.tcp://[email protected]:9090]
Мастер подтверждает, что старому узлу больше не будет разрешено присоединяться (хотя, похоже, есть ошибка, см. первую строку — gated instead for akka.tcp://[email protected]:9090 ms
, которая, как я полагаю, будет временем, когда он должен быть закрыт):
[WARNING][07/12/2015 20:39:36][Thread 0013][remoting] Association to [akka.tcp://[email protected]:9090] with unknown UID is reported as quarantined, but address cannot be quarantined without knowing the UID, gated instead for akka.tcp://[email protected]:9090 ms
[DEBUG][07/12/2015 20:39:36][Thread 0015][[akka://InventoryService/system/endpointManager/reliableEndpointWriter-akka.tcp%3a%2f%2fInventoryService%400.0.0.0%3a9090-2/endpointWriter]] Disassociated [akka.tcp://[email protected]:8090] -> akka.tcp://[email protected]:9090
[DEBUG][07/12/2015 20:39:36][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Association to [akka.tcp://[email protected]:9090] having UID [1198519768] is irrecoverably failed. UID is now quarantined and all messages to this UID will be delivered to dead letters. Remote actorsystem must be restarted to recover from this situation.
[WARNING][07/12/2015 20:39:36][Thread 0013][remoting] Association to [akka.tcp://[email protected]:9090] having UID [1198519768] is irrecoverably failed. UID is now quarantined and all messages to this UID will be delivered to dead letters. Remote actorsystem must be restarted to recover from this situation.
Рабочий загружается и пытается подключиться к мастеру:
[DEBUG][07/12/2015 20:40:20][Thread 0013][remoting] Associated [akka.tcp://[email protected]:8090] <- akka.tcp://[email protected]:9090
[DEBUG][07/12/2015 20:40:21][Thread 0023][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:21][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:23][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:28][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:33][Thread 0023][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:38][Thread 0022][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:43][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:48][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:53][Thread 0023][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:40:58][Thread 0022][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:41:03][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:41:08][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:41:13][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
[DEBUG][07/12/2015 20:41:18][Thread 0023][[akka://InventoryService/system/cluster/core/daemon]] [Initialized] Received Akka.Cluster.InternalClusterAction+InitJoin
Что здесь происходит?
Рабочий:
Загрузка резервной копии после убийства:
[DEBUG][07/12/2015 20:40:18][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Uninitialized] Received Akka.Cluster.InternalClusterAction+JoinSeedNodes
[DEBUG][07/12/2015 20:40:18][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Uninitialized] Received Akka.Cluster.InternalClusterAction+Subscribe
[DEBUG][07/12/2015 20:40:18][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Uninitialized] Received Akka.Cluster.InternalClusterAction+JoinSeedNodes
[DEBUG][07/12/2015 20:40:20][Thread 0021][[akka://InventoryService/system/cluster/core/daemon]] [Uninitialized] Received Akka.Cluster.InternalClusterAction+Subscribe
[DEBUG][07/12/2015 20:40:18][Thread 0020][[akka://InventoryService/system/cluster/core/daemon]] [Uninitialized] Received Akka.Cluster.InternalClusterAction+Subscribe
[DEBUG][07/12/2015 20:40:21][Thread 0015][[akka://InventoryService/system/endpointManager/reliableEndpointWriter-akka.tcp%3a%2f%2fInventoryService%40127.0.0.1%3a8090-1/endpointWriter]] Drained buffer with maxWriteCount: 50, fullBackoffCount: 1,smallBackoffCount: 0, noBackoffCount: 0,adaptiveBackoff: 10000
И все... в лог больше ничего не записывается!
Полные файлы журнала:
Конфигурация главного кластера:
cluster {
seed-nodes = ["master's address here"]
roles = [ InventoryServiceMaster, InventoryServiceWorker ]
failure-detector {
acceptable-heartbeat-pause = 5s
threshold = 10.0
}
}
Конфигурация воркера такая же, но только с ролью InventoryServiceWorker
.
Что мне здесь не хватает? Это проблема конфигурации? (Надеюсь, это не ошибка — я видел, как кто-то другой сообщил о похожей проблеме на Github).
РЕДАКТИРОВАТЬ:
Просто чтобы прояснить, я не использую Akka.dll
из Nuget, поскольку он содержит ошибку сериализации — я проверил, применил ли текущий мастер исправление и выполнил сборку Release. В журналах есть отладочная информация, потому что я сохранил PDB из сборки.
РЕДАКТИРОВАТЬ 2:
В рабочем журнале после перезагрузки событие Akka.Cluster.InternalClusterAction+JoinSeedNodes
появляется дважды, потому что у меня изначально был ручной вызов Cluster.JoinSeedNodes()
. С тех пор я удалил это, но результат все тот же.