为每个用户维护有界列表的最佳 Cassandra 数据模型
Best Cassandra data model for maintaining bounded lists per user
我有包含用户与网站交互的 Kafka 流,因此每个事件都有时间戳和有关事件的信息。对于每个用户,我想在 Cassandra 中存储最后 K 个事件(例如 100 个事件)。
我们的网站不断遇到机器人/大量用户,这就是我们想要限制事件的原因,只是为了考虑 "normal" 用户。
我目前在 Cassandra 中拥有当前数据模型:
user_id, event_type, timestamp, event_blob
其中
<user_id, event_type> = partition key, timestamp = clustering key
现在,我们会在新事件发生后立即在 Cassandra 中写入一条新记录,稍后我们会清理 "heavier" 个分区(即事件计数 > 100)。
这不会实时发生,除非我们不清理沉重的分区,否则我们有时会在读取时遇到严重的延迟。
对于这种情况,您有更好的 table 设计建议吗?
有没有办法告诉 Cassandra 最多只存储 K 个分区元素,并以 FIFO 方式使旧元素过期?或者有更好的 table 设计可供我选择吗?
您现有实施的问题在于删除会创建墓碑,最终会导致读取延迟。不建议创建过多的墓碑。
基于计数(每个分区的行数)的 FIFO 实现是不可能的。对于您的用例,更好的方法是不要删除同一 table 中的记录。使用 Spark 将 table 迁移到新的临时 table 并删除迁移过程中的额外记录。类似于:
1) 创建一个新的 table
2) 使用 Spark,从原始 table 读取,迁移所有必需的记录(过滤额外记录)并写入新的临时文件 table.
3) 截断原始 table。请注意,截断操作不会创建墓碑。
4) 使用 Spark 将所有内容从临时 table 迁移回原始 table。
5) 截断温度 table.
您可以在维护 window 应用程序时执行此操作(大约一个月一次),然后您可以限制每个分区 100 次的读取。
Do you have any suggestions of a better table design for such case?
在为此类场景进行数据建模时,我推荐一种利用三样东西的模式:
- table 上设置的默认 TTL。
- 按时间分量降序聚类。
- 调整查询以使用时间戳的范围,从不查询超过 TTL 的数据。
TTL:
later on we go and clean up "heavier" partitions
清理发生之前(平均)多长时间?我会做的一件事是在 table 上使用 TTL,将其设置为您的团队通常必须清理它们之前的最长时间。
集群键,降序:
所以您的 PRIMARY KEY 定义如下所示:
PRIMARY KEY ((user_id,event_type),timestamp)
确保您也在时间戳上按降序进行聚类。
WITH CLUSTERING ORDER BY (timestamp DESC)
这对于与您的 TTL 结合使用很重要。在这里,您的墓碑在分区的 "bottom" 上(按 timestamp
降序排序时),最近的数据(您关心的数据)在分区的 "top" 上。
范围查询:
最后,确保您的查询在 timestamp
上有一个范围组件。
例如:如果今天是11号,我的TTL是5天,那么我可以在不拉回墓碑的情况下查询最近4天的数据:
SELECT * FROM events
WHERE user_id = 11111 AND event_type = 'B'
AND timestamp > '2020-03-07 00:00:00';
我有包含用户与网站交互的 Kafka 流,因此每个事件都有时间戳和有关事件的信息。对于每个用户,我想在 Cassandra 中存储最后 K 个事件(例如 100 个事件)。
我们的网站不断遇到机器人/大量用户,这就是我们想要限制事件的原因,只是为了考虑 "normal" 用户。
我目前在 Cassandra 中拥有当前数据模型:
user_id, event_type, timestamp, event_blob
其中
<user_id, event_type> = partition key, timestamp = clustering key
现在,我们会在新事件发生后立即在 Cassandra 中写入一条新记录,稍后我们会清理 "heavier" 个分区(即事件计数 > 100)。 这不会实时发生,除非我们不清理沉重的分区,否则我们有时会在读取时遇到严重的延迟。
对于这种情况,您有更好的 table 设计建议吗? 有没有办法告诉 Cassandra 最多只存储 K 个分区元素,并以 FIFO 方式使旧元素过期?或者有更好的 table 设计可供我选择吗?
您现有实施的问题在于删除会创建墓碑,最终会导致读取延迟。不建议创建过多的墓碑。
基于计数(每个分区的行数)的 FIFO 实现是不可能的。对于您的用例,更好的方法是不要删除同一 table 中的记录。使用 Spark 将 table 迁移到新的临时 table 并删除迁移过程中的额外记录。类似于:
1) 创建一个新的 table
2) 使用 Spark,从原始 table 读取,迁移所有必需的记录(过滤额外记录)并写入新的临时文件 table.
3) 截断原始 table。请注意,截断操作不会创建墓碑。
4) 使用 Spark 将所有内容从临时 table 迁移回原始 table。
5) 截断温度 table.
您可以在维护 window 应用程序时执行此操作(大约一个月一次),然后您可以限制每个分区 100 次的读取。
Do you have any suggestions of a better table design for such case?
在为此类场景进行数据建模时,我推荐一种利用三样东西的模式:
- table 上设置的默认 TTL。
- 按时间分量降序聚类。
- 调整查询以使用时间戳的范围,从不查询超过 TTL 的数据。
TTL:
later on we go and clean up "heavier" partitions
清理发生之前(平均)多长时间?我会做的一件事是在 table 上使用 TTL,将其设置为您的团队通常必须清理它们之前的最长时间。
集群键,降序:
所以您的 PRIMARY KEY 定义如下所示:
PRIMARY KEY ((user_id,event_type),timestamp)
确保您也在时间戳上按降序进行聚类。
WITH CLUSTERING ORDER BY (timestamp DESC)
这对于与您的 TTL 结合使用很重要。在这里,您的墓碑在分区的 "bottom" 上(按 timestamp
降序排序时),最近的数据(您关心的数据)在分区的 "top" 上。
范围查询:
最后,确保您的查询在 timestamp
上有一个范围组件。
例如:如果今天是11号,我的TTL是5天,那么我可以在不拉回墓碑的情况下查询最近4天的数据:
SELECT * FROM events
WHERE user_id = 11111 AND event_type = 'B'
AND timestamp > '2020-03-07 00:00:00';