奇怪的Cassandra ReadTimeoutExceptions,取决于哪个客户端正在查询

时间:2015-05-19 16:30:49

标签: java cassandra cassandra-2.0

我有三个Cassandra节点的集群,其默认配置或多或少。最重要的是,我有一个由两个节点组成的Web层,用于负载平衡,两个Web节点一直在查询Cassandra。一段时间后,随着存储在Cassandra中的数据变得非常重要,一个且仅有一个Web节点开始在特定查询上获得ReadTimeoutException。 Web节点在各个方面都是相同的。

查询非常简单(?是占位符的日期,通常是当前时刻前几分钟):

SELECT * FROM table WHERE time > ? LIMIT 1 ALLOW FILTERING;

使用此查询创建表:

CREATE TABLE table (
    user_id varchar,
    article_id varchar,
    time timestamp,
    PRIMARY KEY (user_id, time));
CREATE INDEX articles_idx ON table(article_id);

当它超时时,客户端等待的时间超过10秒,这绝对是cassandra.yaml中为大多数连接和读取配置的超时。

有几件令我困惑的事情:

  • 查询仅在其中一个Web节点执行它时超时 - 其中一个节点总是失败,其中一个节点总是成功。
  • 当我从cqlsh运行它时,查询立即返回(虽然从我那里运行它时它似乎只能命中一个节点)
  • 还有其他查询需要花费2-3分钟(比10秒超时要长很多)完全没有超时

我无法在Java中跟踪查询,因为它超时了。在cqlsh中跟踪查询并没有提供太多的见解。我不想改变Cassandra超时,因为这是生产系统,我想首先用尽非侵入性选项。 Cassandra节点都有足够的堆,它们的堆远未满,GC时间似乎正常。

我们非常感谢任何想法/方向,我完全没有想法。 Cassandra版本是2.0.2,使用com.datastax.cassandra:cassandra-driver-core:2.0.2 Java客户端。

1 个答案:

答案 0 :(得分:3)

我注意到的一些事情:

  1. 当您使用time作为群集密钥时,它并没有真正帮助您,因为您的查询不受分区键(user_id)的限制。 Cassandra只通过在分区中聚类来命令。所以现在你的查询正在拉回第一行,它满足你的WHERE子句,以散列标记值user_id排序。如果你真的有数千万行,那么我希望这个查询每次都从同一user_id(或相同的少数几个)中提取数据。

  2. “虽然它从我那里运行时似乎只能点击一个节点” 实际上,您的查询只能点击运行它们时的一个节点。将网络流量引入查询会使其变得非常慢。我认为cqlsh中的默认一致性是ONE。这就是卡罗的想法发挥作用的地方。

  3. article_id的基数是什么?请记住,二级索引在“中间路线”基数上运行得最好。高(唯一)和低(布尔)都很糟糕。

  4. 不应在(生产)应用程序端代码中使用ALLOW FILTERING子句。像往常一样。如果此表中有5000万行,则ALLOW FILTERING首先将所有行拉回,然后根据WHERE子句调整结果集。

  5. 建议:

    1. Carlo可能会尝试尝试不同(较低)的一致性级别。尝试在应用程序中设置ONE的一致性级别,看看是否有帮助。

    2. 执行ALLOW FILTERING查询,二级索引查询。他们都很糟糕,但绝对不能同时做到这两点。我也不会用。但是如果我不得不选择,我希望辅助索引查询比允许过滤查询少得多。

    3. 为了在您描述的范围内充分解决这个问题,我会将数据复制到查询表中。看起来您关心的是组织时间敏感数据以及获取最新数据。像这样的查询表应该这样做:

      CREATE TABLE tablebydaybucket ( user_id varchar, article_id varchar, time timestamp, day_bucket varchar, PRIMARY KEY (day_bucket , time)) WITH CLUSTERING ORDER BY (time DESC);

    4. 使用您的数据填充此表,然后此查询将起作用:

      SELECT * FROM tablebydaybucket 
      WHERE day_bucket='20150519' AND time > '2015-05-19 15:38:49-0500' LIMIT 1;
      

      这将按day_bucket对您的数据进行分区,并按time对您的数据进行分组。这样,您将不需要ALLOW FILTERING或二级索引。此外,您的查询只能保证一个节点,Cassandra不必将所有行拉回来并在事后应用WHERE子句。并且以DESCending顺序在time上进行群集,可以帮助您最近的行恢复得更快。