我有三个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
中为大多数连接和读取配置的超时。
有几件令我困惑的事情:
cqlsh
运行它时,查询立即返回(虽然从我那里运行它时它似乎只能命中一个节点)我无法在Java中跟踪查询,因为它超时了。在cqlsh
中跟踪查询并没有提供太多的见解。我不想改变Cassandra超时,因为这是生产系统,我想首先用尽非侵入性选项。 Cassandra节点都有足够的堆,它们的堆远未满,GC时间似乎正常。
我们非常感谢任何想法/方向,我完全没有想法。 Cassandra版本是2.0.2,使用com.datastax.cassandra:cassandra-driver-core:2.0.2
Java客户端。
答案 0 :(得分:3)
我注意到的一些事情:
当您使用time
作为群集密钥时,它并没有真正帮助您,因为您的查询不受分区键(user_id
)的限制。 Cassandra只通过在分区中聚类来命令。所以现在你的查询正在拉回第一行,它满足你的WHERE子句,以散列标记值user_id
排序。如果你真的有数千万行,那么我希望这个查询每次都从同一user_id
(或相同的少数几个)中提取数据。
“虽然它从我那里运行时似乎只能点击一个节点” 实际上,您的查询应只能点击运行它们时的一个节点。将网络流量引入查询会使其变得非常慢。我认为cqlsh中的默认一致性是ONE。这就是卡罗的想法发挥作用的地方。
article_id
的基数是什么?请记住,二级索引在“中间路线”基数上运行得最好。高(唯一)和低(布尔)都很糟糕。
不应在(生产)应用程序端代码中使用ALLOW FILTERING子句。像往常一样。如果此表中有5000万行,则ALLOW FILTERING首先将所有行拉回,然后根据WHERE子句调整结果集。
建议:
Carlo可能会尝试尝试不同(较低)的一致性级别。尝试在应用程序中设置ONE
的一致性级别,看看是否有帮助。
执行ALLOW FILTERING查询,或二级索引查询。他们都很糟糕,但绝对不能同时做到这两点。我也不会用。但是如果我不得不选择,我希望辅助索引查询比允许过滤查询少得多。
为了在您描述的范围内充分解决这个问题,我会将数据复制到查询表中。看起来您关心的是组织时间敏感数据以及获取最新数据。像这样的查询表应该这样做:
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);
使用您的数据填充此表,然后此查询将起作用:
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
上进行群集,可以帮助您最近的行恢复得更快。