Несоответствие между трассировкой Cassandra и задержкой на стороне клиента

Мы используем Cassandra 2.0.15 и наблюдаем огромные задержки чтения (> 60 секунд), возникающие через равные промежутки времени (примерно каждые 3 минуты) со всех хостов приложений. Мы измеряем эту задержку вокруг вызовов session.execute(stmt). При этом Cassandra отслеживает продолжительность отчета ‹1 с. Мы также выполняли в цикле запрос через cqlsh с тех же хостов во время этих пиковых задержек, и cqlsh всегда возвращался в течение 1 с. Чем можно объяснить это несоответствие на уровне драйвера Java?

-- редактировать: в ответ на комментарии --

Настройки JVM серверов Cassandra: -XX:+CMSClassUnloadingEnabled -XX:+UseThreadPriorities -XX:ThreadPriorityPolicy=42 -XX:+HeapDumpOnOutOfMemoryError -Xss256k -XX:StringTableSize=1000003 -Xms32G -Xmx32G -XX:+UseG1GC -Djava.net.preferIPv4Stack=true -Dcassandra.jmx.local.port=7199 -XX:+DisableExplicitGC.

GC на стороне клиента незначителен (ниже). Настройки клиента: -Xss256k -Xms4G -Xmx4G, версия драйвера Cassandra 2.1.7.1

Сборщик мусора на стороне клиента незначителен

Код измерения на стороне клиента:

val selectServiceNames = session.prepare(QueryBuilder.select("service_name").from("service_names"))

override def run(): Unit = {
  val start = System.currentTimeMillis()
  try {
    val resultSet = session.execute(selectServiceNames.bind())
    val serviceNames = resultSet.all()
    val elapsed = System.currentTimeMillis() - start
    latency.add(elapsed) // emits metric to statsd
    if (elapsed > 10000) {
      log.info("Canary2 sensed high Cassandra latency: " + elapsed + "ms")
    }
  } catch {
    case e: Throwable =>
      log.error(e, "Canary2 select failed")
  } finally {
    Thread.sleep(100)
    schedule()
  }
}

Код построения кластера:

def createClusterBuilder(): Cluster.Builder = {
  val builder = Cluster.builder()
  val contactPoints = parseContactPoints()
  val defaultPort = findConnectPort(contactPoints)
  builder.addContactPointsWithPorts(contactPoints)
  builder.withPort(defaultPort) // This ends up config.protocolOptions.port
  if (cassandraUsername.isDefined && cassandraPassword.isDefined)
    builder.withCredentials(cassandraUsername(), cassandraPassword())
  builder.withRetryPolicy(ZipkinRetryPolicy.INSTANCE)
  builder.withLoadBalancingPolicy(new TokenAwarePolicy(new LatencyAwarePolicy.Builder(new RoundRobinPolicy()).build()))
}

Еще одно наблюдение, которое я не могу объяснить. Я запустил два потока, которые выполняют один и тот же запрос таким же образом (как указано выше) в цикле, единственная разница в том, что желтый поток спит 100 миллисекунд между запросами, а зеленый поток спит 60 секунд между запросами. Зеленая нить достигает низкой задержки (менее 1 с) гораздо чаще, чем желтая.

введите здесь описание изображения


person Yuri Shkuro    schedule 18.09.2015    source источник
comment
какую версию java-драйвера вы используете?   -  person Schildmeijer    schedule 18.09.2015
comment
Вы отслеживаете события сборки мусора в JVM (на стороне хоста и на стороне клиента)?   -  person Jim Meyer    schedule 18.09.2015
comment
Можете ли вы опубликовать свой код Java, который запрашивает Cassandra?   -  person Aaron    schedule 18.09.2015
comment
Я второй @JimMeyer. Можете ли вы опубликовать доступную оперативную память и настройки JVM? Соблюдают ли они рекомендации, изложенные Datastax? ?   -  person Nathan    schedule 18.09.2015
comment
Я отследил проблему до истечения времени ожидания запросов на узлах из удаленного центра обработки данных. Кластер имеет узлы в двух контроллерах домена, но пространство ключей реплицируется только внутри локального контроллера домена, поэтому удивительно, что даже рассматривалось удаление узлов. Мне удалось снизить задержку, (а) изменив согласованность с ОДНОЙ на ЛОКАЛЬНУЮ_ОДНУ и (б) перейдя с простого балансировщика нагрузки с циклическим перебором на балансировщик с поддержкой DC (также с использованием поддержки задержек и токенов). Почему драйвер пытается связаться с удаленными хостами для нереплицированного пространства ключей?   -  person Yuri Shkuro    schedule 20.09.2015


Ответы (2)


Это обычная проблема, когда вы получаете компонент для проверки самого себя.

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

Наиболее вероятным объяснением является второе. Скажем, у вас есть очередь из 100 задач, но поскольку система работает медленно, каждая задача занимает 1 секунду. Вы измеряете каждую задачу внутренне, и она видит, что это заняло 1 секунду, однако добавьте 100 задач в очередь, и первая запустится через 0 секунд, но последняя запустится через 99 секунд, а затем сообщает, что это заняло 1 секунду, но с вашей точки зрения на завершение ушло 100 секунд, из которых 99 секунд ждали начала.

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

person Peter Lawrey    schedule 18.09.2015
comment
Я мог видеть, что это рассуждение применимо, если компонент (кластер Cassandra) думал, что отвечает быстро, но клиенты видели иначе. В моем случае у меня есть два разных клиента, работающих на одной машине, и измеряя их взаимодействие с компонентом, один клиент получает ответы последовательно быстро, другой видит большую задержку. - person Yuri Shkuro; 19.09.2015

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

  1. изменение согласованности с ONE на LOCAL_ONE и
  2. переход от простого циклического балансировщика нагрузки к контроллеру с поддержкой DC (также с использованием поддержки задержек и токенов).

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

person Yuri Shkuro    schedule 29.09.2015