#java #apache-zookeeper #apache-curator
Вопрос:
У меня есть CuratorFramework
клиент (v5.1.0), работающий на сервере Zookeeper (v3.7.0). Если сервер Zookeeper выключен, пока клиент подключен к нему, я могу видеть состояния соединения (с a ConnectionStateListener
) SUSPENDED
, а затем LOST
и больше ничего, даже когда сервер возвращается в сеть.
Это похоже на очень стандартный вариант использования, и я, должно быть, упускаю что-то глупое, но я никогда не смогу заставить клиента подключиться снова, как только сервер будет подключен.
Я провел некоторый поиск в Google и не нашел ничего полезного о том, как справиться с восстановлением после ПОТЕРЯННОГО состояния.
У меня есть автономный пример того, что я делаю с примером кода в классе CuratorRecoveryTest (выполняется в среде IDE, а не в maven). Его мясо (извлечено из тестового класса):
// setup the server and client
server = new TestingServer();
client = newClient(server.getConnectString(), 60000, 15000, new RetryNTimes(1, 250));
client.start();
client.blockUntilConnected();
// add the listener
final var stateListener = new StateListener();
stateListener.stateChanged(client, CONNECTED);
// register the listener
client.getConnectionStateListenable().addListener(stateListener);
// verify connection
assertTrue(client.getZookeeperClient().isConnected());
// let things settle
nap(3, "initial settling");
// stop zk
stopServer();
log.info(">>>>>>>>>> STOPPED ZK SERVER");
// let it bake
nap(3, "letting things bake");
// ensure disconnected
assertFalse(client.getZookeeperClient().isConnected());
nap(3, "disconnecting");
// start zk
server.start();
log.info(">>>>>>>>>> STARTED ZK SERVER");
await().atMost(5, MINUTES).until(() -> stateListener.getCurrentState() == CONNECTED || stateListener.getCurrentState() == RECONNECTED);
// NOTE: it never gets here - no state changes after LOST
assertTrue(client.getZookeeperClient().isConnected());
Когда это выполняется, я получаю следующий вывод:
[Thread-0] INFO org.apache.curator.test.TestingZooKeeperMain - Starting server
[Thread-0] WARN org.apache.zookeeper.server.ServerCnxnFactory - maxCnxns is not configured, using default value 0.
[main] INFO org.apache.curator.framework.imps.CuratorFrameworkImpl - Starting
[main] INFO org.apache.curator.framework.imps.CuratorFrameworkImpl - Default schema
[main] WARN demo.CuratorRecoveryTest - CONNECTION-STATE-CHANGE: null --> CONNECTED
[main] DEBUG demo.CuratorRecoveryTest - Taking a 3s nap for initial settling...
[main] DEBUG demo.CuratorRecoveryTest - Done napping for initial settling...
[Curator-ConnectionStateManager-0] WARN demo.CuratorRecoveryTest - CONNECTION-STATE-CHANGE: CONNECTED --> SUSPENDED
[main] INFO demo.CuratorRecoveryTest - >>>>>>>>>> STOPPED ZK SERVER
[main] DEBUG demo.CuratorRecoveryTest - Taking a 3s nap for letting things bake...
[main] DEBUG demo.CuratorRecoveryTest - Done napping for letting things bake...
[main] DEBUG demo.CuratorRecoveryTest - Taking a 3s nap for disconnecting...
[main] DEBUG demo.CuratorRecoveryTest - Done napping for disconnecting...
[main] INFO demo.CuratorRecoveryTest - >>>>>>>>>> STARTED ZK SERVER
[Curator-ConnectionStateManager-0] WARN org.apache.curator.framework.state.ConnectionStateManager - Session timeout has elapsed while SUSPENDED. Injecting a session expiration. Elapsed ms: 20009. Adjusted session timeout ms: 20000
[main-EventThread] WARN org.apache.curator.ConnectionState - Session expired event received
[Curator-ConnectionStateManager-0] WARN demo.CuratorRecoveryTest - CONNECTION-STATE-CHANGE: SUSPENDED --> LOST
что затем завершается неудачей, когда условие ожидания никогда не выполняется.
ПРИМЕЧАНИЕ: Это происходит и в более старой версии комбинации Куратора и Смотрителя зоопарка, так что это не проблема «кровоточащего края».
Чего мне не хватает?
Комментарии:
1. Спасибо, я могу воспроизвести ваш код на github. Но если я удалю
server.close
и заменю вашstart
на arestart
, это приведет к успешному повторному подключению клиента. Вероятноserver.close
, это означает, что тестовый сервер не может быть запущен снова. Возможно, добавьте свою оригинальную дорожку в производство к вашему вопросу? Я испытываю вашу проблему и подозреваю, что это связано с ошибкой в использовании кураторомZooKeeper.updateServerList
метода.2. Этот тест предназначен для имитации отключения сервера zookeeper (возможно, на несколько минут), а затем повторного запуска — не уверен, что предлагаемые вами изменения все еще отражают это. На самом деле нет трассировки стека как таковой, а просто поток сообщений «не удается подключиться» в журнале. Я могу воспроизвести его с помощью реального сервера, но это трудно представить в тесте. Мне придется изучить тот метод, о котором вы упомянули.
3. ОБНОВЛЕНИЕ: Похоже, что это немного отвлекающий маневр.
TestingServer
Он ведет себя не так, как настоящий сервер, когда он убит и запущен снова. Когда я пытаюсь выполнить тот же сценарий со стандартным сервером ZK, он нормально подключается после потери. Моя проблема, должно быть, исходит откуда-то из моего служебного кода. Я, вероятно, закрою этот вопрос.4. ОБНОВЛЕНИЕ-2: У меня просто возникла мысль, что причина, по которой сервер тестирования не работает для меня, заключается в том, что он, вероятно, запускается во второй раз на другом порту, чем в первый — мне придется изучить это и опубликовать обновление или закрыть вопрос.
Ответ №1:
ZookeeperFactory
, который не использует предыдущий устаревший IP-адрес, а вместо этого использует исходное неразрешенное имя хоста.
Короче говоря, при создании куратора назначьте пользовательский ZookeeperFactory
CuratorFramework zkClient = CuratorFrameworkFactory
.builder()
...
.zookeeperFactory(new ZKClientFactory())
где это ZKClientFactory
создает новое Zookeeper
из кэшированного connectString
.