绑定分区生长的Cassandra主键选择



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

第一个想法是使用客户ID和某个时间间隔的组合键。有没有其他更好、更有机的选择?

因为我们想要尽可能少的分区读取,所以我想简单地使用年份来为每个分区的每个客户设置数据的上限。但是,如果我没弄错的话,这会使数据分布相当不均匀。这个问题可以通过几个月甚至几周/几天来解决吗?

我相信这是一个经常出现的问题,我对听到人们实施的各种解决方案很感兴趣。

编辑:为了更清楚地了解查询类型,他们将计算每个客户在大时间片上的聚合。理想情况下,我们只需要这样:

PRIMARY KEY ((customer_id), timestamp)

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

一个分区可以容纳大量的行,但是如果您多年来的容量将是一个问题,您可以从哈希表中借鉴一个想法。当多个值散列到一个值时,额外的值存储为溢出链表。

我们可以将同样的思想扩展到分区。当大容量客户的分区"填满"时,我们将额外的分区添加到列表中。

你可以这样定义你的表:

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

对于大多数客户,您只需将bucket设置为0并使用单个分区。但是,如果0分区变得太大,则向静态列表添加1,以表明您现在也将数据存储在bucket 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和year进行分区,但是为了进行查询,您需要以某种方式知道开始和结束年份。使用溢出方法,第一个桶是主桶,并且具有标准的已知值,例如读的值为0。但缺点是需要进行读操作才能知道要写入哪个bucket,但是如果每个客户在通信会话期间生成大量事件,那么可能开销不会太大。

最新更新