时间序列数据的 Cassandra 分区键

Cassandra partition key for time series data

我正在测试 Cassandra 作为时间序列数据库。

我创建数据模型如下:

CREATE KEYSPACE sm WITH replication = {
  'class': 'SimpleStrategy',
  'replication_factor': 1
};

USE sm;

CREATE TABLE newdata (timestamp timestamp,
  deviceid int, tagid int,
  decvalue decimal,
  alphavalue text,
  PRIMARY KEY (deviceid,tagid,timestamp));

在Primary key中,我设置了deviceid作为partition key,这意味着所有具有相同设备id的数据将写入一个节点(它是指一台机器还是一个分区。每个分区最多可以有20亿行)也如果我在同一节点内查询数据,检索速度会很快,对吗?我是 Cassandra 的新手,对分区键和集群键有点困惑。

我的大部分查询如下:

我将有大约 2000 个 deviceid,每个 deviceid 将有 60 tagid/value 对。不知道会不会是一大排deviceid, timestamp, tagid/value, tagid/value...

I’m new to Cassandra and a bit confused about the partition key and clustering key.

听起来您了解分区键,所以我只想补充一点,您的分区键可以帮助 Cassandra 确定在集群中的哪个位置(哪个令牌范围)存储您的数据。每个节点负责几个主要令牌范围(假设 vnodes)。当您的数据写入数据分区时,它会按您的集群键排序。这也是它在磁盘上的存储方式,因此请记住,您的集群键决定了数据在磁盘上的存储顺序。

Each partition can have max 2 billion rows

这不完全正确。每个分区最多可支持 20 亿个 单元 。一个单元格本质上是一个列 name/value 对。你的集群键自己加起来就是一个单元格。因此,通过计算为每个 CQL 行存储的列值来计算单元格,如果使用聚类列,则再添加一个。

根据您的宽行结构,您的行数限制可能远少于 20 亿行。此外,这只是存储限制。即使您设法在单个分区中存储 100 万个 CQL 行,查询该分区也会 return 如此多的数据,以至于它会很笨拙并且可能会超时。

if I query data within the same node, the retrieval will be fast, am I correct?

它至少比命中多个节点的多键查询要快。但它是否 "fast" 取决于其他因素,例如行的宽度,以及执行删除和就地更新等操作的频率。

Most of my query will be as below:

select lastest timestamp of know deviceid and tagid
Select decvalue of known deviceid and tagid and timestamp
Select alphavalue of known deviceid and tagid and timestamp
select * of know deviceid and tagid with time range
select * of known deviceid with time range

您当前的数据模型可以支持所有这些查询,但最后一个除外。为了在 timestamp 上执行范围查询,您需要将数据复制到新的 table 中,并构建一个 PRIMARY KEY 来支持该查询模式。这称为 "query-based modeling." 我会像这样构建一个查询 table:

CREATE TABLE newdata_by_deviceid_and_time (
  timestamp timestamp,
  deviceid int,
  tagid int,
  decvalue decimal,
  alphavalue text,
  PRIMARY KEY (deviceid,timestamp));

table 可以支持在 timestamp 上进行范围查询,而在 deviceid 上进行分区。

但我看到的这两种模型中的最大问题是 "unbounded row growth." 基本上,随着您为设备收集越来越多的值,您将接近每个分区 20 亿个单元的限制(并且再说一遍,在那之前事情可能会变得很慢)。您需要做的是使用一种称为 "time bucketing."

的建模技术

例如,我会说我确定按月分桶将使我很好地保持在 20 亿个单元格限制以下 并且 允许日期范围灵活性的类型我需要。如果是这样,我将添加一个额外的分区键 monthbucket 并且我的(新)table 将如下所示:

CREATE TABLE newdata_by_deviceid_and_time (
  timestamp timestamp,
  deviceid int,
  tagid int,
  decvalue decimal,
  alphavalue text,
  monthbucket text,
  PRIMARY KEY ((deviceid,monthbucket),timestamp));

现在,当我想查询特定设备和日期范围内的数据时,我还会指定 monthbucket:

SELECT * FROM newdata_by_deviceid_and_time
WHERE deviceid='AA23' AND monthbucket='201603'
AND timestamp >= '2016-03-01 00:00:00-0500'
AND timestamp < '2016-03-16 00:00:00-0500';

请记住,monthbucket 只是一个例子。对您来说,使用季度甚至年份可能更有意义(假设您一年中每个 deviceid 没有存储太多值)。