DynamoDB为时间序列数据集避免了SCAN

时间:2016-01-14 00:12:38

标签: time-series amazon-dynamodb

我有兴趣计算两个时间点之间具有唯一可识别资源的用户交互。

我的用例是:

  1. 检索个人resourceId的总计数(在时间x和时间y之间)
  2. 生成按计数排序的前resourceId列表(时间x和时间y之间)
  3. 理想情况下,我想使用DynamoDB实现这一目标。在发电机中对时间序列数据进行排序看起来有它的挑战,并且在尝试对数据建模时遇到了一些反最佳实践。

    目前为止的数据模型

    下采样表格可能如下所示,其中countresourceId范围内与timebin的互动次数。

    | resourceId    | timebin   | count |
    |---------------|-----------|-------|
    |(Partition Key)| (Sort Key)|       |
    

    每个资源的总交互计数是具有相同resourceId的每个项目中的count属性的总和。由于无限制的“所有时间”计数是有意义的,旧的事件永远不会过时,但它们可以进一步下采样并进入更大的时间段。

    使用上面的模式用例1 是通过使用它的散列键对资源进行排队并使用排序键强制执行时间约束来实现的。然后可以在应用方计算总计数。

    对于用例2 ,我希望获得相当于SQL GROUP BY resourceId, SUM(count)的功能。为此,无论timebin如何,数据库都需要返回与提供的resourceId约束匹配的所有项目。然后可以在应用方执行对计数的分组和求和。

    问题:使用上述架构,需要进行全表扫描。

    这显然是我想避免的。

    可能的解决方案

    1. 严重缓存用例2 的查询,以便使用扫描,但很少(例如每天一次)。
    2. 维护一个聚合表格,例如,预定义timeRange s作为分区键,相应的count作为排序键。
    3. | resourceId | timeRange (partition)  | count (sort) |
      |------------|------------------------|--------------|
      |  1234      | "all_time"             | 9999         |
      |  1234      | "past_day"             | 533          |
      

      此处,“all_time”具有固定的FROM日期,因此每次收到resourceId事件时都可以递增。但是,“past_day”具有移动日期,因此需要使用更新的FROM和TO标记定期重新聚合。

      我的问题

      是否有更有效的方法来建模这些数据?

1 个答案:

答案 0 :(得分:1)

根据您对表的描述,其中resourceId是表的哈希键,如果您在单个哈希键中执行聚合,则可以使用查询来完成此操作。此外,如果timebin(范围键)可以使用大于和小于运算符进行比较,您将能够通过有效查询直接获取所需的记录,然后总结应用程序端的计数。

但是,这不会达到你的第二点,因此需要额外的工作来满足这两个要求。

维护聚合表似乎是全球领导者董事会的合理方法。我建议将DynamoDB Streams与AWS Lambda一起使用,以近乎实时地维护该聚合表。这遵循AWS最佳实践。

定期扫描和聚合方法也是有效的,根据您的表格大小可能更实用,因为它更直接实现,但有许多事情需要注意......

确保扫描的进程与主应用程序执行逻辑分开。实时填充此缓存是不切实际的。如果表中的项目数量只有几百或更少,则表扫描仅适用于实时请求。

确保对您的扫描进行速率限制,以便此过程不会消耗所有IOPS。或者,您可以在此时间段内大幅提高IOPS,然后在流程完成后降低然后返回。另一种方法是制作一个尽可能窄的GSI进行扫描,将GSI专用于此过程将避免需要速率限制,因为它可以消耗它想要的所有IOPS而不会影响该表的其他用户。