我想从许多来源在Cassandra中存储数据,并且每小时运行一次作业来处理特定小时的数据点。用于此的最佳模式是什么?
为避免出现热点,我无法将所有数据放在一个分区中一小时,因此每小时的数据需要分布在多个分区中。
所以我看到两种方法允许按小时查询:
为每小时创建一个新表,并执行没有where子句的表的select *来读取该小时。我认为这对读写很有效,但是要管理这么多表会很烦人。
每周创建一个新表,并在一周内有一个小时数列(即1到168),并在其上创建一个二级索引。然后我可以做一个select * where hour = x。这似乎有效,但我担心如果有很多行,它不会很好地扩展。
有谁知道哪种方法会更好地扩展?有更好的方法吗?
感谢。
答案 0 :(得分:3)
在这样的情况下,您可以使用"水桶"。桶是将分区分成几个单独部分的方法。例如,假设您的架构如下:
CREATE KEYSPACE timeseries WITH replication = {
'class' : 'SimpleStrategy', 'replication_factor' : 1
};
USE timeseries;
CREATE TABLE hourly (
source_id text,
hour text,
date timestamp,
data text,
bucket int,
PRIMARY KEY ((hour, bucket), date)
);
然后你可以使用bucket
使用某个已知标识符的哈希函数(例如source_id
)将小时分成例如10个分区。
在查询时,您需要指定hour
并且通常指定所有存储桶:
SELECT * FROM hourly WHERE hour = '2015-07-20 23:00' AND bucket IN (0,1,2,3,4,5,6,7,8,9);
哈希函数非常重要,因为您希望它在不同分区之间均匀分布数据,即使已识别的哈希值不是均匀分布的,但您也不希望它是一个非常复杂的函数。
这个JSFiddle为您提供了一个示例散列函数,它非常简单,统一分发数据,并且可以使用任何语言轻松复制:http://jsfiddle.net/joscas/yfp72fq5/
否则代替散列函数,你的id的模数甚至是纪元时间的模数都可以满足而不是散列函数,但是如果你使用id的模数,你必须检查这些数字是否为'以均匀的方式结束。另一方面,如果你采用时间戳的模数,你将有效地将所有内容写入一个桶中,如果桶的数量很小,这可能会产生热点。
答案 1 :(得分:1)
您没有多少选择,正如您已经发现的那样,解决方案存在缺陷。
由于与二级索引相关的可伸缩性问题,我肯定会避免使用解决方案2。如果您现在需要解决方案,我会使用很多表。如果您可以等待,我可以使用Cassandra 3和materialized views选择合适的密钥。
HTH, 卡罗