我正在处理一个涉及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/