Повторное подключение к Cassandra node при запуске
Я хочу использовать Docker для запуска моего приложения и базы данных Cassandra, и я хотел бы использовать Docker Compose для этого. К сожалению, Cassandra запускается гораздо медленнее, чем мое приложение, и поскольку мое приложение с нетерпением инициализирует объект Cluster
, я получаю следующее исключение:
com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: cassandra/172.18.0.2:9042 (com.datastax.driver.core.exceptions.TransportException: [cassandra/172.18.0.2:9042] Cannot connect))
at com.datastax.driver.core.ControlConnection.reconnectInternal(ControlConnection.java:233)
at com.datastax.driver.core.ControlConnection.connect(ControlConnection.java:79)
at com.datastax.driver.core.Cluster$Manager.init(Cluster.java:1454)
at com.datastax.driver.core.Cluster.init(Cluster.java:163)
at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:334)
at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:309)
at com.datastax.driver.core.Cluster.connect(Cluster.java:251)
Согласно stacktrace и небольшой отладке, кажется, что драйвер Java Cassandra не применяет политики повтора к первоначальному запуску. Мне это кажется странным. Есть ли способ настроить драйвер, чтобы он продолжал попытки подключения к серверу до тех пор, пока он не завершится?
Ответы
Ответ 1
Вы должны иметь возможность написать логику try/catch в NoHostAvailableException, чтобы повторить соединение после 5-10 секунд ожидания. Я бы рекомендовал сделать это несколько раз, прежде чем бросать исключение через определенный период времени, когда вы знаете, что он должен был начать с этой точки.
Пример псевдокода
Connection makeCassandraConnection(int retryCount) {
Exception lastException = new IllegalStateException();
while (retryCount > 0) {
try {
return doConnectionStuff();
} catch (NoHostAvailableException e) {
lastException = e;
retryCount--;
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
}
}
throw lastException;
}
Ответ 2
Если вы не хотите изменять код клиента, а контейнер-докер-клиент клиентского приложения останавливается из-за ошибки, вы можете использовать следующий атрибут для клиентского приложения в файле документации для док-станции.
restart: unless-stopped
Это перезапустит контейнер клиентского приложения столько раз, сколько это произойдет. Пример файла docker-compose.yml:
version: '2'
services:
cassandra:
image: cassandra:3.5
ports:
- "9042:9042"
- "9160:9160"
environment:
CASSANDRA_CLUSTER_NAME: demo
app:
image: your-app
restart: unless-stopped
Ответ 3
Драйвер Datastax нельзя настроить таким образом.
Если это только проблема с Docker, и вы не хотите менять свой код, вы можете подумать о том, чтобы использовать что-то вроде wait-for-it который представляет собой простой script, который будет ожидать прослушивания TCP-порта перед запуском приложения. 9042 является родным транспортным портом cassandra.
Другие варианты обсуждаются здесь в документации докеров, но я лично использовал только wait-for-it, но нашел, что это полезно при работе с кассандрой внутри докеров.
Ответ 4
Если вы организуете много докеров, вы должны пойти на сборку докеров, в зависимости от тега
version: '2'
services:
cassandra:
image: cassandra:3.5
ports:
- "9042:9042"
- "9160:9160"
environment:
CASSANDRA_CLUSTER_NAME: demo
app:
image: your-app
restart: unless-stopped
depends_on:
- cassandra
Ответ 5
Попробуйте увеличить тайм-аут соединения, это одна вещь иногда происходит на AWS и тому подобное. Я думаю, что вы смотрите на поздний этап в журнале ошибок, в какой-то момент он должен сказать вам, что он не может подключиться из-за тайм-аута или недоступной сети, а затем он помещает узлы как недоступные.
Используя phantom, код выглядит следующим образом:
val Connector = ContactPoints(Seq(seedHost))
.withClusterBuilder(_.withSocketOptions(
new SocketOptions()
.setReadTimeoutMillis(1500)
.setConnectTimeoutMillis(20000)
)).keySpace("bla")
Ссылка на ресурс:
com.datastax.driver.core.exceptions.NoHostAvailableException # 445