Azure数据表-将RowKey正确用作DateTime.Ticks吗?

Ove*_*ack 4 c# azure azure-storage

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

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

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

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

[PartitionKey][RowKey][TimeStamp][SensorSerial][Reading][Type]
Run Code Online (Sandbox Code Playgroud)

这是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]
Run Code Online (Sandbox Code Playgroud)

我将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))));
Run Code Online (Sandbox Code Playgroud)

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

因此,为了解决此问题,我计划将其用作RowKey值

var RowKey = string.Format("{0:D19}", DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks);
Run Code Online (Sandbox Code Playgroud)

这将满足此查询并返回必要的值:

TableQuery<Readings> query = new TableQuery<SensorEntity>().Where(
TableQuery.CombineFilters(
(TableQuery.GenerateFilterCondition("SensorSerial", QueryComparisons.Equal, "xxxx")), 
TableOperators.And,
(TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, 
"2519084875883616261"))));
Run Code Online (Sandbox Code Playgroud)

但是,在这里我可能是错的,由于以下原因这种方法可能会引起一些问题

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

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

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

Gau*_*tri 6

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

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

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

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

可能的解决方案

一种可能的解决方案(现在考虑将查询针对某个传感器)是为每个传感器创建一个单独的表,然后将该传感器的数据存储在指定的表中。我看到的这种方法的优点是:

  • 由于每个传感器都有自己的表,因此您实际上已经释放了一个键。在这种情况下,您可以将其PartitionKey用作反向刻度和RowKey其他所需的值。我建议使用较高的粒度(例如一个小时)存储刻度线,PartitionKey并保持RowKey相同。这样可以确保您最终不会创建很多分区。
  • 由于每个传感器数据都存储在单独的表中,因此您可以将它们放在不同的存储帐户中。所以SensorAtable可以在Storage Account ASensor Btable可以在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组合在表中必须是唯一的。因此,我认为这不会成为问题。