我在Cassandra 2.1.3上为时间序列应用程序创建数据模型。我们将为系统的每个用户保留X数据量,并且我想知道为此要求设计的最佳方法是什么。
使用'桶'在分区键中,因此X时段的数据进入同一行。像这样:
((id, bucket), timestamp) -> data
我可以一次删除一行,但代价是维护此存储桶概念。它还限制了我可以在timestamp
上查询的范围,可能会导致多次查询。
将所有数据存储在同一行中。 N列删除每列。
(id, timestamp) -> data
范围查询再次简单。但是在删除多列后的性能呢?
鉴于我们计划使用TTL让数据过期,两种型号中的哪一种可以提供最佳性能?是Option1的逻辑删除开销<< Option2还是两个模型上每列都会有一个墓碑?
我试图避免将自己埋葬在墓碑墓地里。
答案 0 :(得分:3)
我认为这将取决于您计划为您最终选择的给定分区键计划的数据量,TTL是什么以及您正在进行的查询。
我通常倾向于选项#1,特别是如果所有写入的TTL都相同。此外,如果您使用LeveledCompactionStrategy或DataTieredCompactionStrategy,Cassandra将在同一个SSTable中保存来自同一分区的数据,这将极大地提高读取性能。
如果您使用选项#2,同一分区的数据可能会分布在多个级别(如果使用LCS)或一般只有多个sstables,这可能会导致您从大量SSTable中读取,具体取决于性质你的疑问还有热点问题,如果你有一个非常宽的分区,你可以重载特定的cassandra节点。
#1(您提到的)的另一个好处是,您可以轻松删除整个分区,从而创建一个便宜得多的单个墓碑标记。此外,如果您使用相同的TTL,则该分区中的数据将同时到期。
我确实同意,在多个分区中进行多个查询读取时会有点痛苦,因为它会将一些复杂性推向应用程序端。如果无法隐式确定,您可能还需要维护一个单独的表来跟踪给定id的存储桶。
就性能而言,您是否认为在应用程序进行查询时您需要阅读跨分区?例如,如果您查询“最近的1000条记录”并且分区通常比此更宽,则可能只需要对选项#1进行1次查询。但是,如果您想要查询“给我所有记录”,则选项#2可能更好,否则您需要对每个存储桶进行查询。
答案 1 :(得分:2)
创建上述表格后:
CREATE TABLE option1 (
... id bigint,
... bucket bigint,
... timestamp timestamp,
... data text,
... PRIMARY KEY ((id, bucket), timestamp)
... ) WITH default_time_to_live=10;
CREATE TABLE option2 (
... id bigint,
... timestamp timestamp,
... data text,
... PRIMARY KEY (id, timestamp)
... ) WITH default_time_to_live=10;
我插入了一个测试行:
INSERT INTO option1 (id,bucket,timestamp,data) VALUES (1,2015,'2015-03-16 11:24:00-0500','test1');
INSERT INTO option2 (id,timestamp,data) VALUES (1,'2015-03-16 11:24:00-0500','test2');
......等了10秒,跟踪查询,我看到每张桌子都有相同的墓碑数。所以无论哪种方式,我都不应该为你担心。
真正的问题是,如果您认为每个分区达到20亿列的限制,那么选项#1是安全的。如果您有大量数据,那么选项#1可能会表现得更好(因为您将无需查看与您的bucket
不匹配的分区),但实际上任何一个都应该没问题在这方面。
<强> TL;博士; 强>
无论您选择哪种选项,性能和墓碑的问题都会相似,我认为选项#2是更好的选择,只是因为查询的简易性。