Мы используем 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 с) гораздо чаще, чем желтая.