Cassandra 主键选择限制分区增长

Cassandra Primary Key Selection to Bound Partition Growth

我们目前正在测试 Cassanda 作为大量通信事件元数据的数据库。由于大多数查询仅限于单个客户,因此按客户 ID 进行分片是有意义的。然而,这意味着分区将随着时间的推移无限增长。我正在努力想出一个看起来足够干净的解决方案。

第一个想法是使用客户 ID 和某个时间间隔的组合键。是否有其他选择,可能会更好并且更有机地增长?

由于我们希望尽可能少地读取分区,所以我想简单地使用年份来为每个分区的每个客户设置数据上限。但是,如果我没记错的话,这会使数据分布不均。这可以通过移动到几个月甚至 weeks/days 来解决吗?

我确信这是一个经常出现的问题,我很想听听人们提出的各种解决方案。

编辑:为了在查询类型上更加清晰,他们将计算每个客户在大时间片上的聚合。理想情况下,我们只会有这个:

主键((customer_id),时间戳)

但是,正如我所提到的,这将导致多年来每个分区的无限增长。

好吧,一个分区可以容纳大量的行,但是如果您担心多年来的体积,您可以借鉴散列 tables 的想法。当多个值散列为一个值时,多余的值将存储为溢出链表。

我们可以将相同的想法扩展到分区。当一个分区用于大批量客户时 "fills up",我们将额外的分区添加到列表中。

因此您可以这样定义 table:

CREATE TABLE events (
    cust_id int,
    bucket int, 
    ts int,
    overflow list<int> static,
    PRIMARY KEY ((cust_id, bucket), ts));

对于大多数客户,您只需将存储桶设置为零并使用单个分区。但如果零分区太大,则向静态列表添加 1 以指示您现在也在存储桶 1 中存储数据。然后您可以根据需要向列表添加更多分区。

例如:

INSERT INTO events (cust_id, bucket, ts) VALUES (123, 0, 1);
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 0, 2);

SELECT * from events;

 cust_id | bucket | ts | overflow
---------+--------+----+----------
     123 |      0 |  1 |     null
     123 |      0 |  2 |     null

现在假设您想开始为该客户使用第二个分区,只需将其添加到静态列表即可:

UPDATE events SET overflow = overflow + [1] WHERE cust_id=123 and bucket=0;
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 1, 3);
INSERT INTO events (cust_id, bucket, ts) VALUES (123, 1, 4);

所以要检查客户是否正在使用任何溢出桶分区:

SELECT overflow FROM events WHERE cust_id=123 and bucket=0 limit 1;

 overflow
----------
      [1]

现在您可以对分区进行范围查询:

SELECT * FROM events WHERE cust_id=123 and bucket IN(0,1) AND ts>1 and ts<4;

 cust_id | bucket | ts | overflow
---------+--------+----+----------
     123 |      0 |  2 |      [1]
     123 |      1 |  3 |     null

您可以将 "bucket" 定义为您想要的任何含义,例如年份或其他。请注意,溢出列表被定义为静态的,因此每个分区只存储一次,而不是每个事件行。

可能更传统的方法是按 cust_id 和年份进行分区,但是您需要以某种方式知道开始年份和结束年份才能进行查询。使用溢出方法,第一个存储桶是主存储桶并且具有标准的已知值,例如 0 用于读取。但缺点是您需要进行读取才能知道要写入哪个存储桶,但如果每个客户在通信会话期间生成大量事件,那么开销可能不会太多。