Cassandra表定义/分区/建模

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cassandra表定义/分区/建模相关的知识,希望对你有一定的参考价值。

尝试为我们的场景定义正确的架构/表:我们有几百个电子商务站点,每个站点都有独特的siteId

每个站点都有自己的最终用户,每月最多可达1000万个唯一身份用户。每个用户都有独特的userId

每个最终用户都与网站进行交互:查看产品,将产品添加到购物车并购买产品(我们称之为用户事件)。我想存储过去30天的活动(如果可能,则存储180天)。

需要考虑的事项:

  • 网站规模不同!我们有一些拥有1000万终端用户的“重型”网站,但我们也有“轻型”网站,拥有数百/数千名用户。
  • 事件没有唯一的ID。
  • 用户可以一次拥有多个事件,例如,他们可以查看包含多个产品的页面(但我们可以在没有此限制的情况下生活,以简化)。
  • 粗略估计:100个客户x 10M EndUsers x 100交互= 100,000,000,000行(每月)
  • 写入实时(当事件到达服务器时)。阅读量少得多(1%的事件)。
  • 事件具有更多元数据,不同事件(view / purchase / ..)具有不同的元数据。
  • 使用Keyspace在站点之间分离,并管理每个站点与一个表中的所有客户的表。
  • 如何在这里定义密钥? +--------+---------+------------+-----------+-----------+-----------+ | siteId | userId | timestamp | eventType | productId | other ... | +--------+---------+------------+-----------+-----------+-----------+ | 1 | Value 2 | 1501234567 | view | abc | | | 1 | cols | 1501234568 | purchase | abc | | +--------+---------+------------+-----------+-----------+-----------+

我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面所假设的,大约有100个事件。

编辑2:我想这不清楚,但用户的唯一性是每个网站,如果他们在不同的网站上,两个不同的用户可能具有相同的ID

答案

如果要查询userid,则userid应该是复合主键的第一部分(这是分区键)。使用复合主键创建可以查询以返回排序结果的列。我会建议以下架构:

CREATE TABLE user_events (
       userid long,
       timestamp timestamp,
       event_type text,
       site_id long,
       product_id long,
PRIMARY KEY (userid, site_id, timestamp, product_id));

这应该像查询一样

SELECT * FROM user_events WHERE user_id = 123 and site_id = 456;

非常高效。通过将时间戳添加到PK,您还可以轻松限制查询以获得最高(最新)1000(无论您需要)事件,而不会因为具有很长历史的高活跃用户(或机器人)而导致性能问题。

要记住一件事:我建议将user_id或user_id,site_id组合作为分区键(主键的第一部分)。这样可以防止你的行变得太大。

所以替代设计看起来像这样:

CREATE TABLE user_events (
       userid long,
       timestamp timestamp,
       event_type text,
       site_id long,
       product_id long,
PRIMARY KEY ( (userid, site_id), timestamp, product_id));

这种方法的“缺点”是您始终必须提供用户和站点ID。但我想这是你必须做的事情,对吧?

指出一件事。分区键(也称为行id)标识一行。一行将保留在特定节点上。出于这个原因,最好让行或多或少具有相同的大小。具有几千或几十列的行不是真正的问题。如果您有一些包含数百万列的行和其他只有10-20列的行,您将会遇到问题。这将导致集群失衡。此外,它使行缓存效率降低。在您的示例中,我建议避免将site_id作为分区键(行键)。

这对你有意义吗?也许这篇文章的优秀答案会给你一些更多的内容:difference between partition-key, composite-key and clustering-key。此外,仔细看看datastax documentation的这一部分提供了更多细节。

希望有所帮助。

另一答案

我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面所假设的,大约有100个事件。

所以,你想要给定用户的所有事件。由于每个用户在站点上都有唯一的ID,因此您可以使用useridsite_id作为主键并使用timestamp作为聚类键来构建表。这是表结构:

    CREATE TABLE user_events_by_time (
         userid bigint,
         timestamp timestamp,
         event_type text,
         product_id bigint,
         site_id bigint,
         PRIMARY KEY ((site_id,userid), timestamp)
    ) WITH CLUSTERING ORDER BY (timestamp DESC) ;

现在,您可以使用以下查询在给定时间内查询所有用户的事件:

SELECT * from user_events_by_time WHERE site_id= <site_id> and userid = <user_id> and timestamp > <from_time> and timestamp < <to_time>;

希望这能解决你的问题。

以上是关于Cassandra表定义/分区/建模的主要内容,如果未能解决你的问题,请参考以下文章

「时序数据库」Cassandra时间序列大规模数据建模

Apache Cassandra:为小表建模

Cassandra中的数据建模简单表不起作用

Cassandra分页和令牌功能;选择分区键

如何在同一个分区中保留 2 个 Cassandra 表

Cassandra 分区键可以跨一个键空间中的多个表吗?