Cassandra 时间序列数据分区键

问题描述 投票:0回答:1

我正在测试 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));

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

我的大部分查询如下:

  • 选择已知 deviceid 和 tagid 的最新时间戳
  • 选择已知 deviceid 和 tagid 以及时间戳的十进制值
  • 选择已知deviceid和tagid以及时间戳的alpha值
  • 选择已知设备 ID 和标记 ID 的 * 以及时间范围
  • 选择具有时间范围的已知设备 ID 的 *

我将有大约 2000 个 deviceid,每个 deviceid 将有 60 个 tagid/值对。我不确定它是否会是一排宽的 deviceid、时间戳、tagid/值、tagid/值....

cassandra cql cqlsh
1个回答
27
投票

我是 Cassandra 新手,对分区键和集群键有点困惑。

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

每个分区最多可以有 20 亿行

这并不完全正确。 每个分区最多可支持 20 亿个cell。 单元格本质上是一个列名称/值对。 并且您的聚类键本身会添加到一个单元格中。 因此,通过计算为每个 CQL 行存储的列值来计算单元格,如果您使用聚类列,则再添加一个。

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

如果我在同一个节点内查询数据,检索速度会很快,对吗?

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

我的大部分查询如下:

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
执行范围查询,您需要将数据复制到新表中,并构建一个主键来支持该查询模式。 这称为“基于查询的建模”。 我会建立一个这样的查询表:

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

该表可以支持

timestamp
上的范围查询,同时在
deviceid
上进行分区。

但是我发现这两个模型的最大问题是“无限制的行增长”。 基本上,当您为设备收集越来越多的值时,您将接近每个分区 20 亿个单元的限制(同样,在此之前事情可能会变得很慢)。 您需要做的是使用称为“时间桶”的建模技术。

举个例子,我会说我确定按月存储将使我远远低于 20 亿个单元格限制并且允许我需要的日期范围灵活性类型。 如果是这样,我将添加一个额外的分区键

monthbucket
,我的(新)表将如下所示:

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
没有存储太多值)。

© www.soinside.com 2019 - 2024. All rights reserved.