【问题标题】:Time series data in Cassandra, keyspace per month instead of one keyspace?Cassandra中的时间序列数据,每个月的键空间而不是一个键空间?
【发布时间】:2016-08-01 10:01:07
【问题描述】:

我们有数以千计的传感器产生我们想要存储在 Cassandra 中的测量时间序列数据。 我们目前每天存储约 5 亿条记录,这个数量将在下一次增长 5-10 倍。

我们主要使用最新的测量数据。几乎没有读取旧的测量数据。

  • 我们主要从最新的测量数据(即一周前)中读取数据,
  • 较旧的测量值(即小于一个月的年龄)很少被读取(每周十次),
  • 非常旧的测量值(即 1-6 个月大)很少被读取(每月一次),
  • 超过 6 个月的测量被认为是冷的,即从未读取过。

作为压缩策略,我们使用 DTCS。 设置 ttl 不是一个选项,因为我们需要存储测量数据以进行存档。

我还不确定如何处理“旧数据几乎是冷的”这一事实。

更新: 我要避免的事情:在我的 Cassandra 集群中拥有 20 TB 的空间,其中 18 TB 被使用,假设每年只使用一次,如果有的话。我不想为不需要的 18 TB 付费。设置 ttl 不是一个选项,因为我们应该能够读取数据,例如,从 2013 年 3 月开始(此类请求的额外成本是可以的)。如果我们将 ttl 设置为例如 6 个月,那么我们将无法正确执行此操作。

我们目前正在评估两种设计方案,并寻找最具成本效益的方案:

  1. 一个键空间,带有分区键(sensor_id、measurement_date)
  2. 每个月一个键空间,具有相同的分区键(sensor_id、measurement_date)

(在这两种情况下,每行最多有 500K 列,大多少于 100K)

2.的缺点是我们将有

我的问题: 对于我们的用例来说,2. 是一个合理的选择,还是在 Cassandra 中这被视为反模式?

感谢您的帮助!

【问题讨论】:

  • > 每个传感器每天最多可以进行 500k 次测量。我想知道你使用什么样的压缩。总计 5 亿个/每个传感器 50 万个 = 1000 - 目前只有 1000 个传感器。让我们假设每个传感器有 10 个指标。因此,如果您可以压缩每个系列,您可能不需要一个大的键命名空间。这是数字数据(0/1)还是模拟数据,观察到什么样的差异。您需要保持精确的值(大十进制)吗?

标签: cassandra time-series


【解决方案1】:

不建议跨一系列相同的键空间或表对数据进行分区,因为两者都旨在保存有关数据的架构和元数据详细信息,并且应根据分区/集群键实现实际的数据分区。

虽然使用快照备份数据不能按预期按月进行,但您可能可以将 incremental backups 与自定义解决方案一起使用,将刷新的 sstables 一起存储一个月。对于删除数据,使用 TTL 仍然是处理时间序列数据并确保您没有耗尽磁盘空间的最常用方法。

【讨论】:

  • > "将刷新的 sstables 一起存储一个月的自定义解决方案" 是否有一种简单的方法可以确定包含某个月份数据的所有 sstables?然后可以再次单独删除/重新导入这些 sstables 吗?如果我必须为这样的自定义解决方案付出一些努力,我不知道跨“每月”相同的键空间进行分区是否不那么痛苦,知道这不是一个常见的用例......我只是想避免一种情况正如这里所描述的那样grokbase.com/t/cassandra/user/145gfh72kc/…
  • 您可以简单地每月移动增量备份。之后,您可以通过将它们移回 Cassandra 节点来恢复它们。关于删除旧数据的要求;由于您已经在使用 DTCS,Cassandra 应该能够在所有包含的数据都已通过 TTL 过期后删除 SSTables。
【解决方案2】:

通常,您不希望在单独的键空间中拥有较旧的冷数据,因为这将难以维护(正如您所提到的)。现在,由于您对数据进行分区的方式,您的挑战似乎是非常宽的行。相反,我建议您按月“存储”数据。这可以通过修改分区键来完成,如下所示:

PRIMARY KEY ((year,month,sensor_id), measurement_date)

额外的括号是用于将多个列声明为分区键的 CQL 语法。这意味着您将始终必须提供年、月和 sensor_id 才能从该表中读取。但是请记住,Cassandra 主键(与关系数据库不同)定义了数据在集群中的分布方式。如此有效地,我们正在做的是将传感器数据按一年一个月的时间排列在自己的行中。因此,我们基本上通过多个键空间实现了您的想法,但采用了更加 Cassandra 和开发人员友好的方式。

要将数据插入此表中将非常容易。假设 measure_date 是一个 timeuuid(否则您可能会覆盖数据),这是您的代码将执行的一般流程:

  1. 为当前时间生成一个timeuuid (UUIDv1)
  2. 从 timeuuid 中获取年份和月份部分
  3. 然后为 INSERT 执行 CQL:

    • INSERT INTO time_series (year,month,sensor_id,measurement_date) VALUES (2016,4,'sensor_id','generated timeuuid here');

就像我之前提到的,从表格中读取数据应该非常简单。如果您想了解更多信息,我会提供与您的数据建模问题 here 相关的更长回复。

由于您每天要编写 500K 测量值,因此您将需要进一步存储这些数据(有关更多详细信息,请参见上面的 SO 答案),因为通常当您对超过 10k 的聚类列进行聚类时,C* 开始表现不佳。

最后,您可能想阅读Optimizing Cold SS Tables,因为它提供了一些很好的信息。例如,您可以调整cold_reads_to_omit,这样您就不会浪费时间压缩非常冷的表。对于 DTCS,您可以设置 max_sstable_age_days 以停止压缩特定年龄的 SS 表以节省冷表上的 IO。

更新:存储大小管理: 如果您想继续只使用一张桌子来处理所有事情,那么您可以进行一些调整。首先确保表使用压缩(最好是 lz4),接下来您可以降低复制因子,这也可以节省空间。我想如果您对旧数据和新数据有不同的键空间,您可以为每个数据使用不同的 RF 以节省空间。

对于您推送和需要归档的数据量,我建议您研究时间序列数据库 (TSDB),例如 Graphite 和 InfluxDB。对于您的目标和挑战,TSDB 将比使用 Cassandra 来处理时间序列数据更容易使用和执行。

【讨论】:

  • 我每天对每个传感器进行多达 500k 次测量。如果我按月分区,我最终会得到 15M 宽的列。无论如何,分区键并不能解决如何高效管理大量冷数据的问题。
  • 它没有解决冷数据问题,您担心什么?这种数据模型将有效地存储冷数据。当您通过时间桶时,您将停止写入该分区,并且永远不会再次写入。并且 C* 也不必担心它的压缩(请参阅编辑响应中的冷 SS 表调整)。您可能需要调整时间桶的大小以限制您在每个分区中拥有多少冷数据(低至周、日、小时、分钟等),这意味着您必须在应用程序端做更多工作才能读取所有内容(不要在分区键上使用 IN)。
  • 感谢您的帮助!可能我的问题不清楚。我在问题中添加了“更新”部分。冷数据的问题基本上是我需要更多的 Cassandra 节点来保存冷数据。存储应该很便宜,是的,但在我的用例中,我仍在纠结这是否是最具成本效益的方法。
  • @siggi_42 刚刚更新了一些存储调整选项。此外,您可能还想研究时间序列数据库,因为它们更适合您的用例。
猜你喜欢
  • 2018-04-08
  • 1970-01-01
  • 1970-01-01
  • 2019-08-16
  • 2023-03-27
  • 2014-04-18
  • 2020-01-01
  • 2016-12-22
  • 2017-01-01
相关资源
最近更新 更多