Cassandra数据建模物联网最佳实践

时间:2018-11-14 21:54:32

标签: cassandra data-modeling iot cassandra-3.0

我对Cassandra还是陌生的,我正在尝试了解如何为物联网传感器设计表格。

这个想法是拥有多个设备,每个设备上都连接有多个传感器,这些设备定期发送数据(每个传感器每天每个设备最多约200000个值)

我希望能够或多或少实时地查询传感器的最新值,以获取特定的传感器和设备列表。此外,设备并非总是发送数据,并且可能会长时间关闭。

大量阅读后,我想到了类似的东西

CREATE TABLE "sensor_data" (
    deviceid TEXT,
    sensorid TEXT,
    ts timestamp,
    value TEXT,
    PRIMARY KEY ((deviceid, sensorid), ts)
) WITH CLUSTERING ORDER BY (ts DESC);

其背后的想法是对每个设备和传感器(例如

)执行一次查询
Select deviceid, sensorid, ts, value where deviceid = "device1" and sensorid = "temperature" limit 1

并为每个设备和传感器运行此程序。不是全部返回一个查询(这是理想的选择),但似乎足够快,可以为几个设备运行多达100个左右的传感器(可能并行化查询)。

但是,到目前为止,我了解到这会给我的行增加很多列,并且在长期存储和Cassandra限制方面可能会很复杂。

我认为也许在表中添加诸如日期之类的内容(如在某些博客和指南中看到的那样)可能是个好主意

CREATE TABLE "sensor_data" (
    deviceid TEXT,
    sensorid TEXT,
    date TEXT
    ts timestamp,
    value TEXT,
    PRIMARY KEY ((deviceid, sensorid, date), ts)
) WITH CLUSTERING ORDER BY (ts DESC);

然后像这样查询

Select deviceid, sensorid, date, ts, value where deviceid = "device1" and sensorid = "temperature" and date = "2018-11-14" limit 1

那还有意义吗?感觉这可能会减轻存储问题并允许将来更轻松地归档旧数据,但是如果该设备停机一天或更长时间,我该如何查询特定传感器和设备的最新值?我是否真的需要查询1天,如果什么都没找到,请查询前一天,依此类推(也许将其限制在最近几天左右)?

在Cassandra中是否有更好的方法来解决这个问题?或者我的方向正确吗?

1 个答案:

答案 0 :(得分:3)

您会遇到的部分问题是,每个传感器每天都会有20万个读数。通常,您希望将每个分区都保留在100k rows下。因此,您的第二个想法(将日期作为PK的一部分)可能存在性能问题。

您真正想要做的就是我们所说的“存储桶”;如何将事物组合在一起,以便查询可用和高效。

要真正帮助您解决此问题,我们需要了解更多信息:

  • 您有多少台设备?这个数字会增加还是有限?
  • 用简单的英语来说,您要回答的查询示例是什么?

根据您的答案将其结合到答案中(如下):

好的,这是一个潜在的主意...

我们确实关心转储,但是试图将其保留在分区中的100k /分区最佳行附近。

您将需要两个表:

  1. 查询表
  2. 传感器表

查找表如下所示:

CREATE TABLE lookup-table (
deviceid TEXT,
sensor-map MAP,
PRIMARY KEY (deviceid)
);
  • deviceid是每个设备的唯一ID
  • sensor-map是给定设备具有的传感器的JSON map以及该特定传感器的相应唯一ID(例如,{温度:183439,湿度:84543292,其他传感器:blah})
  • 这样,每台设备都有一个可用的传感器映射
  • 查询示例为:SELECT * FROM lookup-table WHERE deviceid = 1234;
  • 另一种方法是将每种传感器的单独列和每个传感器的唯一ID作为值

传感器表如下所示:

CREATE TABLE sensor_data (
sensorid TEXT,
sensor_value (whatever data type fits what you need),
ts TIMESTAMP,
reading_date date,
time_bucket int,
PRIMARY KEY ((reading_date, sensorid, time_bucket), ts)
) WITH CLUSTERING ORDER BY (ts DESC);
  1. 由于每个传感器每天将获得20万个读数,并且我们希望将每个分区保持在10万行以下,这意味着我们希望每天为每个传感器进行两个分区
  2. 你怎么斗?您应该将其分为两个部分:每天需要进行存储;每个传感器每天都会得到一个新分区(reading_date),并每天分成两部分(由于您期望的读数量大);上午或下午; AM等于存储区1,PM等于存储区2。或使用24小时制,其中0-1200等于1,1300-2399等于2
  3. 在您的应用程序内提供特定的sensoridtime_bucket来自您实际要求的时间 查询(例如,如果时间为1135小时,则time_bucket = 1)和reading_date来自您查询的实际日期
  4. 由于您正在与ts DESC进行聚类,因此它将检索 给定sensorid的最新读数。所以看起来像 SELECT * from sensor_data WHERE reading_date = 12/31/2017 AND sensorid = 1234 AND time_bucket = 1 LIMIT 1;
  5. 通过将ts保留为聚类列,您将能够保留给定传感器的所有读数;没有一个会被覆盖

重要信息:如果在一天24小时内传感器读数均匀分布,则此方法非常有用。但是,如果您上午阅读大量信息,而下午根本没有阅读,那么这不是一个平衡点,我们必须找出另一种存储方式。但是,我认为您可以了解正在发生的事情。

要查询:

  • 将有一个查询来检索设备拥有的所有sensorid;拥有这些sensorid之后,就可以将其用于下一步了
  • 每个sensor_value的每个sensorid将有 n 个查询
  • 由于我们正在执行存储操作(通过time_bucket),因此您应该在所有分区中均匀分布

最后:按给定的值给我最新的sensorid 为此,有几种不同的方法...

  • 运行Spark作业:为此,您必须提起并移动数据才能运行Spark查询
  • 使用DataStax Enterprise:通过DSE,您具有基于Spark的集成Analytics(分析)组件,因此您可以运行Spark作业,而不必管理单独的Spark集群。披露:我在那里工作,顺便说一句
  • 创建另一个Cassandra(C *)表并进行一些并行写入

对于其他C *表:

CREATE TABLE sensor_by_value (
sensor-value INT,
ts TIMESTAMP,
sensorid TEXT,
reading_date DATE,
time_bucket INT,
PRIMARY KEY ((sensor-value, reading_date), ts)
) WITH CLUSTERING ORDER BY (ts DESC);

您肯定需要在这里花一些时间:

  • 请记住,每个分区不超过10万行
  • 您必须了解可能的值(范围)
  • 每次阅读的频率
  • 如果您有100个设备,100个传感器,并且每个传感器每天最多读取200k,则每天可能有多达2B传感器读数...
  • 通常,我要让我的客户做的是对他们的数据进行一些分析,以了解这些信息,这样您就可以确保对它进行解释
  • 您需要承担多少费用取决于频率
  • 祝你好运! :-)

最终提示

研究压缩策略:特别是time window compaction strategy(TWCS)并添加default_time_to_live

  • 您的数据在初次插入后似乎是不变的

  • TWCS将使压缩的操作开销大大降低,因为您可以在所需的时间范围内对其进行微调

  • default_ttl也将帮助您在不再需要数据时删除数据。

这个答案和/或满足您要回答的查询吗?如果没有,请告诉我们,我们可以进行迭代。

要了解所有这些内容,请访问DataStax Academy进行大量的免费培训。数据建模(DS 220)是一门很棒的课程!