Cassandra跟踪与客户端延迟之间的差异

时间:2015-09-18 16:22:45

标签: java cassandra driver cql cqlsh

我们正在使用Cassandra 2.0.15,并且从所有应用主机中定期(大约每3分钟)出现大量读取延迟(> 60秒)。我们会在调用session.execute(stmt)时测量此延迟。与此同时,Cassandra追踪的报告持续时间<1s。我们还在一个循环中,在这些峰值延迟时间内通过cqlsh从同一主机运行查询,并且cqlsh总是在1s内返回。什么可以解释Java驱动程序级别的这种差异?

- 编辑:回复评论 -

Cassandra服务器JVM设置:-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

Client side GC is negligible

客户端测量代码:

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秒)。

enter image description here

2 个答案:

答案 0 :(得分:3)

当你让一个组件进行自我测试时,这是一个常见的问题。

  • 您可能会遇到相关工具无法看到的延迟。
  • 您的组件不知道请求何时开始。
  • 当JVM停止时,这可以防止您看到您尝试测量的延迟。

最可能的解释是第二个。假设您有100个任务的队列,但由于系统运行缓慢,每个任务需要1秒钟。你在内部对每个任务计时,它看到它需要1秒,但是在队列中添加100个任务,第一个在0秒后开始,但是最后一个在99秒后开始,然后报告花了1秒,但从你的角度来看它需要100秒才能完成,99秒等待开始。

结果可能会延迟到达您,但除非您在处理结果时执行的操作超过数据库所需的操作,否则这种情况不太可能发生。即你可能认为瓶颈在服务器上。

答案 1 :(得分:2)

我将问题跟踪到查询远程数据中心节点的超时问题。群集在两个DC中具有节点,但是密钥空间仅在本地DC中复制,因此甚至考虑删除节点也是令人惊讶的。我能够将延迟降低

  1. 从ONE更改为LOCAL_ONE一致性和
  2. 从普通循环负载均衡器转换为DC感知负载均衡器(也使用延迟感知和令牌感知)。
  3. 在我看来,Java驱动程序中的一个错误是,当数据中心中的密钥空间明显不存在时,它会尝试将远程数据中心的节点用作协调节点。此外,即使以某种方式不可能,我也使用延迟感知策略,该策略应该排除远程DC节点的考虑。