Java 奇怪的Cassandra ReadTimeoutException,取决于正在查询的客户端

Java 奇怪的Cassandra ReadTimeoutException,取决于正在查询的客户端,java,cassandra,cassandra-2.0,Java,Cassandra,Cassandra 2.0,我有一个由三个Cassandra节点组成的集群,具有或多或少的默认配置。最重要的是,我有一个web层,它由两个用于负载平衡的节点组成,两个web节点始终查询Cassandra。一段时间后,随着存储在Cassandra中的数据变得越来越重要,一个且只有一个web节点开始在特定查询上获取ReadTimeoutException。web节点在各个方面都是相同的 查询非常简单(?是日期的占位符,通常在当前时刻前几分钟): 使用此查询创建表: CREATE TABLE table ( user_i

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

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

使用此查询创建表:

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节点都有大量堆,它们的堆远没有满,GC时间似乎很正常


任何想法/指导都将不胜感激,我完全没有想法。Cassandra版本是2.0.2,使用
com.datasax.Cassandra:Cassandra驱动核心:2.0.2
Java客户端

我注意到了几件事:

  • 当您使用
    time
    作为集群键时,它并没有真正帮助您,因为您的查询不受分区键(
    user\u id
    )的限制。Cassandra仅通过在分区内聚集键来排序。因此,现在您的查询正在回调满足WHERE子句的第一行,该行由
    user\u id
    的散列标记值排序。如果您确实有数千万行,那么我希望此查询每次都能从相同的
    用户id
    (或相同的select少数)中提取数据

  • “虽然我从那里运行它时,它似乎只命中一个节点”实际上,您的查询在运行它们时应该只命中一个节点。在查询中引入网络流量会使查询速度非常慢。我认为cqlsh中的默认一致性是1。这就是卡洛的想法发挥作用的地方

  • 文章id
    的基数是多少?记住,二级索引在“中间路线”基数上效果最好。高(唯一)和低(布尔)都不好

  • 不应在(生产)应用程序端代码中使用该子句。一如既往。如果此表中有5000万行,那么ALLOW FILTERING首先将所有行都拉回来,然后根据WHERE子句缩小结果集

  • 建议:

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

  • 执行允许筛选查询或辅助索引查询。他们两个都很烂,但绝对不能同时做这两件事。我也不会用。但如果我必须选择,我希望二级索引查询比允许过滤查询更糟糕

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

    创建表tablebydaybucket(
    用户id varchar,
    第_idvarchar条,
    时间戳,
    day_bucket varchar,
    主键(日期、时间)
    按时间顺序进行聚类(时间描述)

  • 使用数据填充此表,然后此查询将起作用:

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

    这将按
    day\u bucket
    对数据进行分区,并按
    time
    对数据进行聚类。这样,您就不需要允许筛选或二级索引。此外,您的查询保证只命中一个节点,而且Cassandra不必将所有行向后拉,并在事后应用WHERE子句。按降序在
    time
    上进行聚类有助于更快地返回最近的行。

    此表中有多少行?在cqlsh中设置不同的一致性级别,然后重试again@BryceAtNetwork23:非常有洞察力,谢谢!该查询来自应用程序运行状况检查—我们希望数据流是连续的,如果没有新行,则说明有问题(因此,只接收一个用户的记录并不成问题)。实际的应用程序代码只根据使用的id进行选择。在任何情况下,似乎都无法解释为什么从一个框执行查询时会持续失败,而从另一个框执行查询时会持续成功。
    SELECT * FROM tablebydaybucket 
    WHERE day_bucket='20150519' AND time > '2015-05-19 15:38:49-0500' LIMIT 1;