Как избежать запроса, занимающего много времени при добавлении нового узла в кластер - PullRequest
3 голосов
/ 31 мая 2019

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

Мой журнал времени выполнения:


17:49:40.008 [ThreadPoolTaskScheduler-14] INFO  task.DiskCounting - void task.DiskCounting.runJob()  executed in 8 ms
17:50:00.010 [ThreadPoolTaskScheduler-3] INFO  task.DiskCounting - void task.DiskCounting.runJob()  executed in 15010 ms
17:50:15.008 [ThreadPoolTaskScheduler-4] INFO  task.DiskCounting - void task.DiskCounting.runJob()  executed in 10008 ms
17:50:20.008 [ThreadPoolTaskScheduler-16] INFO  task.DiskCounting - void task.DiskCounting.runJob()  executed in 7 ms

Обычно он занимает около 10 мс,и неожиданно занимает 15000 мс при добавлении узла.

И я обнаружил, что он застрял, потому что ожидание новых данных инициализации узла

Журнал Кассандры (новый узел):

INFO  [HANDSHAKE-/194.187.1.52] 2019-05-31 17:49:36,056 OutboundTcpConnection.java:560 - Handshaking version with /194.187.1.52
INFO  [GossipStage:1] 2019-05-31 17:49:36,059 Gossiper.java:1055 - Node /194.187.1.52 is now part of the cluster
INFO  [RequestResponseStage-1] 2019-05-31 17:49:36,069 Gossiper.java:1019 - InetAddress /194.187.1.52 is now UP
INFO  [GossipStage:1] 2019-05-31 17:49:36,109 TokenMetadata.java:479 - Updating topology for /194.187.1.52
INFO  [GossipStage:1] 2019-05-31 17:49:36,109 TokenMetadata.java:479 - Updating topology for /194.187.1.52
INFO  [MigrationStage:1] 2019-05-31 17:49:39,347 ViewManager.java:137 - Not submitting build tasks for views in keyspace system_traces as storage service is not initialized
INFO  [MigrationStage:1] 2019-05-31 17:49:39,352 ColumnFamilyStore.java:411 - Initializing system_traces.events
INFO  [MigrationStage:1] 2019-05-31 17:49:39,382 ColumnFamilyStore.java:411 - Initializing system_traces.sessions

Застрялкогда: Узел /194.187.1.52 теперь является частью кластера

И клиент будет ждать, пока новый узел инициализирует все данные

Что я пробовал:

1. I try use consistency with ONE or QUORUM, and is no difference

2. I try turn replication factor to 1, 2 or 3, and still no difference

Почемуновый узел становится частью кластера, когда этот узел не полностью инициализирует данные.

Есть ли способ решить эту проблему.

Я ожидаю, что при запросе к старому узлу на производительность не влияют толькоожидание нового узла для инициализации данных.


.,.

Я решил эту проблему.

Я пишу неправильную конфигурацию, я позволяю всем узлам становиться семенами даже до того, как они присоединятся к кластеру, это приводит к истечению времени ожидания при добавлении нового узла в кластер.

После исправления.все чтение нормально, но каким-то образом я обнаружил, что тайм-аут запроса вставки во время добавления узла.

Наконец, я настраиваю это, чтобы избежать тайм-аута вставки:

/sbin/sysctl -w net.ipv4.tcp_keepalive_time=60 net.ipv4.tcp_keepalive_intvl=60 net.ipv4.tcp_keepalive_probes=5

, а также изменил conf на limitпропускная способность

stream_throughput_outbound_megabits_per_sec : 100

Действительно, спасибо за помощь.

Ответы [ 2 ]

2 голосов
/ 01 июня 2019

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

Если новый узел медленно по какой-то причине медленно работает, а драйвер отправляет ему запросы, поведение координатора может повлиять на обслуживание вашего запроса.

Что именно делает 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 мс - это, вероятно, разумное число, в зависимости от того, как выглядят задержки с более высоким процентилем.

Все это, как говорится, если вы можете определить, что проблема в том, что новый узел плохо работает как координатор. Стоит понять почему. Добавление спекулятивного выполнения может быть хорошим способом решения этой проблемы, но, вероятно, лучше попытаться понять, почему новый узел так медленно работает. Наличие мониторинга для наблюдения за метриками Кассандры, скорее всего, позволит лучше понять проблему.

2 голосов
/ 31 мая 2019

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

В своем вопросе вы не упоминаете настройки сети или используете облачные экземпляры, которые имеют прямое влияние на эти ограничения, например, экземпляр AWS m3.large будет более ограничен в сетевых возможностях, чем i3 .4xlarge.

Другая переменная, которую следует учитывать, - это конфигурация диска, если вы используете свое собственное оборудование, найдите ограничение в IO настроек ваших дисков; если вы находитесь в облаке, использование хранилища экземпляров, если оно доступно, будет иметь лучшую производительность, чем внешние тома (например, AWS EBS; если это так, убедитесь, что вы включаете опцию «EBS optimized», если ваш экземпляр это позволяет )

Обычно RF 3 с уровнем согласованности Quorum также должен помочь вам предотвратить проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...