我正在处理一个涉及Azure IOT集线器和Azure功能的Azure项目。

我大约有50个传感器,每10秒会向IOT集线器发送一条新消息。

每次Azure IOT Hub收到新消息时,我都想执行一个函数,该函数读取已发送的消息并将其保存到Azure表存储中。

此刻,我对应该使用哪种Azure Table存储设计感到有些困惑。到目前为止,这是我建议的表存储设计:

[PartitionKey][RowKey][TimeStamp][SensorSerial][Reading][Type]

这是Azure存储资源管理器中数据外观的模拟:
 [GroupA][?][2017-05-03T12:20:22.713Z][xxx][60][Temperature]
 [GroupA][?][2017-05-03T12:25:22.713Z][xxx][61][Temperature]
 [GroupA][?][2017-05-03T12:30:22.713Z][xxx][59][Temperature]
 [GroupB][?][2017-05-03T12:35:22.713Z][yyy][90][Humidity]
 [GroupB][?][2017-05-03T12:40:22.713Z][yyy][92][Humidity]

我将RowKey留在“?”目前,因为它与手头的问题有关。

问题是,即我希望能够基于SensorSerial和指定的时间范围来查询表存储数据-例如获取最近15秒钟内的所有xxx读数。

以下查询始终不返回任何数据:
TableQuery<Readings> rangeQuery = new TableQuery<Readings>().Where(
TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("SensorSerial", QueryComparisons.Equal, "xxx"),
    TableOperators.And,
    TableQuery.GenerateFilterConditionForDate("TimeStamp",
    QueryComparisons.GreaterThanOrEqual, DateTime.Now.AddSeconds(-15))));

从到目前为止的内容来看,我不确定为什么会这样-无法基于TimeStamp字段过滤数据。因此,必须将RowKey用作某种伪TimeStamp日期时间刻度字段。

因此,为了解决此问题,我计划将其用作RowKey值
var RowKey = string.Format("{0:D19}", DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks);

这将满足此查询并返回必要的值:
TableQuery<Readings> query = new TableQuery<SensorEntity>().Where(
TableQuery.CombineFilters(
(TableQuery.GenerateFilterCondition("SensorSerial", QueryComparisons.Equal, "xxxx")),
TableOperators.And,
(TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual,
"2519084875883616261"))));

但是,在这里我可能是错的,这种方法可能会导致一些问题,因为以下中的:

如果两个或多个传感器同时/间隔传输数据该怎么办? RowKey必须是唯一的,当一个传感器向Azure存储中插入新行时,另一传感器将无法继续。

我可以运行该代码,希望传输/数据处理/插入会导致足够的延迟,而不会导致任何问题,但是依靠它会很糟糕。

有没有更好的办法?一种更安全的故障排除方法,允许我根据指定的时间和唯一的设备标识符查询Azure数据表存储吗?

最佳答案

让我们先谈谈您当前的方法。

您目前采用的方法还可以。这种方法的好处是,您使用reverse ticks (DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks)可以确保将最新数据添加到表的顶部而不是表的底部,只要您查询的最后x分钟/小时数据,检索将非常快。

后来我发现这种方法存在一些问题:

  • 随着数据的增长,当您希望查询真正的旧数据时,您将遇到Partition Scans发生的情况。这比Full Table Scans更好,但应尽可能避免。
  • 您将所有内容都放在一张表中,因此所有读/写操作都只发生在一张表上,因此最终您将遇到表服务施加的 scalability limits 。这将对性能产生不利影响。

  • 可能的解决方案

    一种可能的解决方案(现在考虑将查询针对某个传感器)是为每个传感器创建一个单独的表,然后将该传感器的数据存储在指定的表中。我看到的这种方法的优点是:
  • 由于每个传感器都有自己的表,因此您实际上已经释放了一个键。在这种情况下,您可以将PartitionKey用作反向刻度,并将RowKey用作您喜欢的任何其他值。我建议为PartitionKey存储更高粒度(例如一小时)的刻度,并保持RowKey相同。这样可以确保您最终不会创建很多分区。
  • 由于每个传感器数据都存储在单独的表中,因此您可能会将它们放在不同的存储帐户中。因此SensorA表可以在Storage Account A中,而Sensor B表可以在Storage Account B中。这样,您实际上可以在不同表/存储帐户之间进行流量负载平衡,并获得更好的可伸缩性和吞吐量。

  • 显然,这种方法的缺点是,它使您增加了更多的管理麻烦。您将需要某种主数据库,以保持传感器及其关联的存储帐户之间的关联。这种方法的另一个缺点是您将无法仅在时间戳上查询(我的第二个问题)。为此,您可以采用所采用的方法在另一个存储帐户中仅保留一个表。

    关于您的注释What if two or more sensors being to transmit data at the same time/interval? RowKey must be unique, the moment one sensor inserts a new row into Azure Storage, the other will no linger be able to.,基本上,RowKey在Partition中必须是唯一的,换句话说,PartitionKey + RowKey组合在表中必须是唯一的。因此,我认为这不会成为问题。

    关于c# - Azure数据表-将RowKey正确用作DateTime.Ticks吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43762117/

    10-16 08:52
    查看更多