DynamoDB 是否适合我需要访问记录和摘要(聚合)信息的每天 1M 事件的场景

Is DynamoDB right for my 1M events-per-day scenario where I need access to both records and summary (aggregate) information

来自 C 世界的软件工程师闯入云端 space。我试图了解我是否可以使用 DynamoDB 来满足我所有的场景需求,如果我根本不应该使用它,或者我是否应该在某些场景中使用 DynamoDB 然后卸载到另一个数据库(可能是更传统的 RDMS)用于其他场景。

我有一堆机器可以将遥测数据发送到我的 AWS API。我目前的想法是将这些事件放在 DynamoDB table 中。在第一年,我预计每天 table 总共有大约 100 万个新条目(平均每秒 > 10 个),峰值时间接近每秒 100 个事件。遥测事件的大小为 0.5-1KB。首先,我只想捕获每个遥测数据并将其记录下来。也就是每天大约 1GB。

我会使用 RDMS,但我担心随着 ACID 属性的增加,我们每秒写入 10 到 100 次,随着数据库大小的增长,数据库访问速度会显着降低。 我是否应该担心,或者传统的 RDMS 是否适合table我的需要?我觉得我不需要 RDMS 的原子保证(我可以忍受最终的一致性),尤其是对于 reading/aggregating 查询。

我在想我的主键是机器 ID(分区)和 time unix 毫秒纪元(排序键)之间的复合键。这应该支持关键场景场景,例如检索特定时间范围和一组机器的所有遥测事件的列表。

然而,还有其他我想做的事情,例如能够获取各种遥测事件的每日总计,例如机器传感器被触发的次数(即计数)。或者列出当一组机器的温度高于特定值时记录的所有遥测事件。遥测事件是异构的 - 有许多类型,例如温度、触发等,我需要能够针对给定的一组 machineID 和时间 window 快速过滤特定类型的遥测事件。

所以你可以想象我的一个查询可能看起来像 'for this time window, and this set of machines, list all temperature (type) telemetry events where a temperature over 70 degrees was recorded'。前 2 个约束来自我的分区 (machineId) 和排序键 (time),但后一个约束将查询所有遥测类型,这些遥测类型是温度并且值大于 70。这是我约束的 4 个字段。我是否应该接受可以查询 machineId 和时间的现实,但必须从该查询的结果 return 中扫描遥测类型和值?

此外,此 dynamodb table 接收遥测数据,但前端需要提供诸如上次接收遥测事件、上次机器服务时间、特定遥测事件的每日计数等事物的摘要信息。我不想每次在前端重新加载摘要页面时都必须重新查询它们。是否应在遥测到达时计算这些聚合,然后将其存储在单独的 table 中(或者如果性能需要,则存储在内存中,例如 redis)。这是技术上的流处理吗?

我在网上看到,好的设计通常只使用一个 table(单个 table 设计),但我发现很难理解如何做到这一点。在我希望能够查看单个遥测事件但又能快速访问聚合信息的情况下,这可能没有意义。

写完这个问题后,我的直觉现在告诉我:

  1. 请使用 dynamodb
  2. 当您摄取遥测事件时,为最常见的用户场景(每小时、每天、每周、每月总计)创建聚合并将它们存储在某个地方以便快速访问。在此处调查流处理 and/or 运动。
  3. 对于需要聚合的不太常见的用户场景,请使用其他技术,如 Redshift、Athena

谢谢, 托马斯

My current idea is to put these events in a DynamoDB table. In the first year I am expecting about 1M new entries total in the table per day (average > 10 per second), with peak times being closer to 100 events per second. The size of the telemetry events will be 0.5-1KB.

听起来像是 DynamoDB 的一个非常好的用例 — 每秒大量相对较小的写入。

I would use RDMS, but I am concerned that with the ACID properties, as the database size grows given we have 10s to 100s writes per second, database access will slow down significantly. Am I right to be concerned, or will a traditional RDMS be suitable for my needs?

RDBMS 可以扩展以处理这种负载,是的。不是微不足道的,但也不是这个世界上的东西。

既然你提到了 DynamoDB,我假设你对 AWS 中的其他服务没问题——我建议你看看 Aurora 的这种东西,if 您决定使用 RDBMS。

但这听起来很浪费,尤其是因为:

I don't feel I need the atomic guarantees of an RDMS (I can live with eventual consistency) especially for reading/aggregating queries.

因此,它指向的不是 RDBMS。不过不一定是 DynamoDB。

不过,您需要注意数据模型。

现在...

Should I accept the reality that [...] will have to scan for the telemetry type and value from the results return in that query?

几乎可以肯定不是。设计基于 DynamoDB 的数据模型,从一开始就要求您扫描越来越多的数据,这是一个非常糟糕的主意。这样下去你以后会讨厌自己的。

这里要牢记的非常重要的一点是,您不希望操作因大小增加而花费更长的时间(例如,就像您对 RDBMS 的担忧)。

扫描操作花费更长的时间 table 越大。因此,随着您在 table 中积累越来越多的数据,您的系统性能会随着时间的推移而下降。例如,您可以通过将“非热”数据从“主要”table 卸载到“存档”table 来解决这个问题。但这增加了管理整个系统的复杂性。

相反,尝试设计您的数据模型,以便操作保持其性能,而不管您拥有的数据总量如何。例如,确保您的查询始终仅限于对一个(或至少 O(1))项集合(即具有相同分区键的项)的操作。

the frontend needs to present summary information [...]. I don't want to have to re-query them every time [...]. Should these aggregates be calculated when the telemetry arrives and then stored in a separate table (or perhaps if performance needs it, in memory something like redis). Is this technically stream processing?

流处理是一种很好的方法。

您完全正确地避免了每次显示前端时都重新计算此摘要信息。 “即时”聚合并将其存储在某个地方是一种非常好的方法。然后前端只需“显示最新的预先计算的数据”:微不足道。

现在,问题变成了何时聚合、存储到哪里以及如果聚合失败怎么办。

  • 何时汇总。

您可以在遥测数据到达时执行此操作,是的,但是如果您要将其写入 DynamoDB,请记住您可以使用 DynamoDB Streams — 每个新项目都被写入一个持久流,可以重播(如果您需要重新计算某些东西),您可以让它自动调用 Lambda 函数,例如,执行聚合。

  • 存储位置。

存储在内存中的风险是您增加了丢失摘要并不得不重新计算它的机会。我希望这里至少有 一些 耐用性。最佳解决方案取决于很多因素,包括您如何为该前端提供服务(静态 html?不可缓存的 API 请求?),以及您希望它多久更新一次(每 X 秒?每条新的遥测数据?)。

您可能想在这里调查的一件事是 Kinesis Data Analytics:它可以 运行 自动为您进行所有聚合,并将结果写入您选择的某个持久存储。然后,您可以决定该摘要如何进入前端(例如,每次都从它那里请求,将其写入 Redis 之类的东西,反转控制并将其推送到服务于前端的服务器,这样他们就不必发出请求,等等) .

  • 如果失败怎么办。

这部分很重要。如果摘要由于处理管道故障而过时,或者如果内存缓存服务器丢失或持久存储不可用导致数据丢失,您不希望前端中断。因此,确保您清楚地了解如何处理这些情况非常重要。

您在这里应该考虑的另一个方面是,如果您失去了当前的聚合,该怎么办。 DynamoDB 包含所有测量值,因此您应该能够重新计算所有摘要。但请记住 — 数据在增长,这将需要扫描,因此从头开始重新计算可能需要很长时间。

假设您正在计算的统计信息,您可能想要编写“检查点”(例如,“第 X 天之前的所有摘要数据”)或更粗略的预聚合(例如,“所有摘要数据仅针对第 X 天”)可以从预聚合中正确导出(例如,你可以用“平均”或“最大”来做;你不能用 p99 来做)。将这些检查点保存到 S3 可能是个好主意。或者,使用我在其他地方提到的多个 DynamoDB table 可能很有用(一个“热”table 正在添加到,一个“非热”table 你移动到归档数据,并且您始终在某处维护此归档 table 的摘要;这样,您只需扫描“热”数据的一小部分。

I read online that good design typically only uses one table (single table design), but I am finding it hard to understand how to get there.

是的...小心点。虽然我不认为它本质上是一个糟糕的设计,但事实是很多人都荒谬地过度炒作它。主要问题是设计的发展变得异常困难。

尽管如此,请记住这是不是 RDBMS。我这么说是因为我觉得那是你更习惯的事情。但是在 DynamoDB 中设计数据模型非常不同(单个 table 或不)。重复数据是其中的正常部分,“正常形式”是不可取的。

要始终牢记的主要一点是,您希望您的读写操作对于数据量都是 O(1),同时您希望能够灵活地查询所有信息你需要的。 Single-table 不会自动给你,也不一定能简化实现它的过程。


After writing out this question, here is what my intuition is telling me right now: [...]

我会说你的直觉很好。正确。

关于第 3 点,Athena 和 Redshift,请记住它们通常更适合“批处理”(尽管不完全适用)。换句话说,例如,您不希望您的前端向其中任何一个发送查询并等待结果。您可能需要一个进程来查询它们中的任何一个并将预先计算的结果存储在例如 S3 上,然后将其显示在您的前端之类的东西上。但它们应该与低延迟请求分开。