Это всего лишь теория, но одной из возможных причин этого является то, что клиент-драйвер выбирает новый узел в качестве координатора, в этом случае уровень согласованности и репликация не являются основным фактором, способствующим задержке обслуживание вашего запроса.
Если новый узел медленно по какой-то причине медленно работает, а драйвер отправляет ему запросы, поведение координатора может повлиять на обслуживание вашего запроса.
Что именно делает runJob
? Вы предположили, что он выполняет один запрос, но возможно ли, что это запрос диапазона?
Если это один запрос, и он занимает 10 секунд, это кажется странным, поскольку по умолчанию read_request_timeout
составляет 5 секунд. Если это запрос диапазона (чтение с участием нескольких разделов), по умолчанию используется значение 10 секунд. Вы настраиваете эти таймауты?
Когда вы видите ответы, которые длинны для одного запроса, что может означать, что координатор препятствует отзывчивости, как в противном случае, если координатор реагировал, а реплики были медленными, вы увидите сообщение ReadTimeoutException
, обслуживаемое клиентом.
Чтобы лучше реагировать на эти случаи, ряд драйверов клиентов реализуют стратегию, называемую «спекулятивное исполнение». Как описано в документации для драйвера DataStax Java для Apache Cassandra :
Иногда узел Кассандры может испытывать трудности (например, длительная пауза GC), и ответ может занять больше времени, чем обычно. Запросы, отправленные на этот узел, будут испытывать большие задержки.
Одна вещь, которую мы можем сделать для улучшения, - это предварительно запустить второе выполнение запроса к другому узлу до того, как первый узел ответит или допустит ошибку. Если этот второй узел отвечает быстрее, мы можем отправить ответ обратно клиенту (мы также отменяем первое выполнение - обратите внимание, что «отмена» в этом контексте означает просто отбрасывание ответа, когда он прибывает позже, Cassandra не поддерживает отмену в полете запросы на данном этапе)
Вы можете настроить свой драйвер для спекулятивного выполнения с постоянным порогом для идемпотентных запросов (таких как чтение). В драйвере Java 3.x это делается следующим образом:
Cluster cluster = Cluster.builder()
.addContactPoint("127.0.0.1")
.withSpeculativeExecutionPolicy(
new ConstantSpeculativeExecutionPolicy(
500, // delay before a new execution is launched
2 // maximum number of executions
))
.build();
В этом случае, если координатор не успел ответить, через 500 мс водитель выберет другого координатора и отправит второй квест, и первый координатор, который ответит, победит.
Обратите внимание, что это может вызвать усиление запросов, отправляемых на ваш кластер в целом, поэтому вы хотите настроить эту задержку таким образом, чтобы она включалась только тогда, когда время отклика сильно аномальное. В вашем случае, если запросы обычно занимают менее 10 мс, 500 мс - это, вероятно, разумное число, в зависимости от того, как выглядят задержки с более высоким процентилем.
Все это, как говорится, если вы можете определить, что проблема в том, что новый узел плохо работает как координатор. Стоит понять почему. Добавление спекулятивного выполнения может быть хорошим способом решения этой проблемы, но, вероятно, лучше попытаться понять, почему новый узел так медленно работает. Наличие мониторинга для наблюдения за метриками Кассандры, скорее всего, позволит лучше понять проблему.