完全复制的 Cassandra 集群上非主键查询的性能

Performance of non-primary-key queries on a fully replicated Cassandra cluster

我已经使用 Docker 个容器在一台机器上设置了一个完全复制的 3 节点 Cassandra 集群,状态如下:

Datacenter: dc_n1
=================
Status Address Load Tokens Owns Host_ID Rack
UN 172.18.0.3 83.98 MiB 256 100.0% 5bf rack_n1

Datacenter: dc_n2
=================
Status Address Load Tokens Owns Host_ID Rack
UN 172.18.0.6 83.52 MiB 256 100.0% 0518 rack_n2

Datacenter: dc_n3
=================
Status Address Load Tokens Owns Host_ID Rack
UN 172.18.0.2 83.52 MiB 256 100.0% ca95 rack_n3

现在考虑以下键空间:

create KEYSPACE Whosebug WITH replication = {'class': 'NetworkTopologyStrategy', 'dc_n1':1,'dc_n2':1,'dc_n3':1};

和 table 定义为(假设 T_notID 是唯一的):

create TABLE Whosebug.TABLE (T_ID int PRIMARY KEY, T_notID int, T_Data text);

当我分派一定数量(比如一百个)并发 Java 线程向 Cassandra 节点提交以下两个 JDBC 查询(重复,持续一分钟)时,我见证了 100 倍的性能删除 (B) 查询:

(A) SELECT T_Data FROM TABLE WHERE T_ID = ?

(B) SELECT T_Data FROM TABLE WHERE T_notID = ? ALLOW FILTERING

(B) 查询还会引发许多 Cassandra 错误: com.datastax.driver.core.exceptions.ReadTimeoutException: Cassandra timeout during read query at consistency ONE (timeout while waiting for repair of inconsistent replica):

我知道,一般来说,在查询中使用 'ALLOW FILTERING' 是一种反模式,应格外小心使用,但在上面的简化示例中,因为数据是 完全复制的 并且每个项目的一个副本驻留在每个节点,我不明白为什么 PK 查询和非 PK 查询表现不同。

换句话说,考虑到这个场景中的 read consistencyONE 并且每个节点都可以响应查询而无需与集群中的其他节点通信(无论主键定义如何), 我本以为 Cassandra 的行为与集中式 SQL 数据库类似。

有人可以向我解释为什么会这样吗and/or我该如何解决?

当您对分区键有条件时 - Cassandra 知道数据在磁盘上的位置,并且可以跳转到分区的开头并按顺序读取数据。但是,如果您有非分区条件,那么您的查询将需要遍历所有数据并仅过滤掉必要的部分 - 您没有任何索引可以让 Cassandra 找出数据所在的位置。

如果你需要经常运行查询T_notID,那么你可以创建物化视图或二级索引(但你需要了解它们有什么限制)。

DataStax 有一个 very good blog post 关于允许过滤和它可以使用的地方。