【问题标题】:Serverless - DynamoDB (terrible) performances compared to RethinkDB + AWS Lambda无服务器 - 与 RethinkDB + AWS Lambda 相比,DynamoDB 的性能(糟糕)
【发布时间】:2019-03-28 18:07:24
【问题描述】:

在将现有 Node.js (Hapi.js) + RethinkDB 从 OVH VPS(最小 vps)迁移到 AWS Lambda(节点)+ DynamoDB 的过程中,我最近遇到了一个非常巨大的性能问题。

用法相当简单,人们使用在线工具,“东西”通过 node.js 服务器/lambda 保存在数据库中。那个“东西”占用了一些空间,大约 3kb 非 gzip 压缩(一个有很多键和子的复杂对象,因此为什么使用 NOSQL 解决方案是有意义的)

保存本身没有问题(目前......),没有多少人使用该工具,也没有太多同时编写的工作,使用 Lambda 而不是 24/7 是有意义的运行 VPS。


真正的问题是我何时想要下载这些结果。

  • 使用 Node+RethinkDB 大约需要 3 秒 扫描整个表并生成 CSV 文件以供下载
  • AWS Lambda + DynamoDB 超时 30秒后,即使我对结果进行分页只下载1000条,仍然需要20秒(这次没有超时,只是很慢)->有2200如果 AWS Lambda 在 30 秒后不超时,我们可以推断出我们需要大约 45 秒来下载整个表

因此,对于相同数量的提取数据,RethinkDB 的操作大约需要 3 秒,理论上 DynamoDB 需要 45 秒。

现在让我们看看这些数据。表中有 2200 个项目,总共 5MB,以下是 DynamoDB 统计信息:

Provisioned read capacity units 29 (Auto Scaling Enabled)
Provisioned write capacity units    25 (Auto Scaling Enabled)
Last decrease time  October 24, 2018 at 4:34:34 AM UTC+2
UTC: October 24, 2018 at 2:34:34 AM UTC

Local: October 24, 2018 at 4:34:34 AM UTC+2

Region (Ireland): October 24, 2018 at 2:34:34 AM UTC

Last increase time  October 24, 2018 at 12:22:07 PM UTC+2
UTC: October 24, 2018 at 10:22:07 AM UTC

Local: October 24, 2018 at 12:22:07 PM UTC+2

Region (Ireland): October 24, 2018 at 10:22:07 AM UTC

Storage size (in bytes) 5.05 MB
Item count  2,195

有 5 个预置读/写容量单位,最大自动缩放为 300。但自动缩放似乎没有像我预期的那样扩展,从 5 变为 29,可以使用 300,这足以下载30 秒内 5MB,但不使用它们(我刚刚开始使用自动缩放,所以我猜它配置错误?)

在这里我们可以看到自动缩放的效果,它确实增加了读取容量单位的数量,但是这样做太晚了,并且已经发生了超时。我尝试连续多次下载数据,并没有真正看到太大的改进,即使是 29 个单元。

Lambda 本身配置了 128MB RAM,增加到 1024MB 没有效果(正如我所料,它确认问题来自 DynamoDB 扫描持续时间)


所以,这一切让我想知道为什么 DynamoDB 不能在 30 秒内做什么 RethinkDB 在 3 秒内做什么,它与任何类型的索引无关,因为操作是“扫描”,因此必须遍历数据库中的所有项目以任何顺序。

我想知道我应该如何使用 DynamoDB 获取巨大的数据集(5MB!)以生成 CSV。

我真的想知道 DynamoDB 是否是适合这项工作的工具,与我过去使用的工具(mongo、rethink、postgre 等)相比,我真的没想到性能如此之低

我想这一切都归结为正确的配置(那里可能有很多需要改进的地方),但即便如此,为什么下载一堆数据如此痛苦? 5MB 不是什么大问题,但感觉需要付出很多努力和关注,而导出单个表只是一个常见的操作(统计信息、用于备份的转储等)


编辑:由于我创建了这个问题,我阅读了https://hackernoon.com/the-problems-with-dynamodb-auto-scaling-and-how-it-might-be-improved-a92029c8c10b,它深入解释了我遇到的问题。基本上,自动缩放的触发缓慢,这解释了为什么它不能根据我的用例正确缩放。如果您想了解 DynamoDB 自动扩展的工作原理,这篇文章是必读的。

【问题讨论】:

  • 如果您在运行 Lambda 函数之前手动将 DynamoDB 表吞吐量更改为 300,而不是依赖自动扩展,会发生什么情况?我认为自动扩展的速度太慢,无法帮助您调用单个 Lambda 函数。此外,如果您的 Lambda 函数在 30 秒时超时,那么您必须以这种方式对其进行配置。您需要增加函数的超时值。此外,增加 Lambda 函数设置中的可用 RAM 也会增加可用 CPU,因此您可以尝试将其提高到最高设置。
  • 30 秒是 Lambda 通过 APIGateway 允许的最大值,所以我无法增加它,我尝试先自动缩放它,认为它可以处理活动峰值,但我不想要当我大部分时间几乎不使用它们但偶尔需要它们时支付 300 RCU
  • 啊,你没有提到你也在使用 API Gateway。这听起来更像是一个可以按计划运行而不是由 API Gateway 触发的后端进程。
  • 是的,没想到要带上这个。关键是在有人需要时下载文件,这样做是有意义的,当使用 RethinkDB 需要几秒钟时,这不是问题 :)

标签: node.js amazon-web-services aws-lambda amazon-dynamodb


【解决方案1】:

DynamoDB 不是为这种用途而设计的。它不像传统的数据库,您可以随意查询,尤其是一次处理大型数据集(例如您请求的数据集)时效果不佳。

对于这种类型的场景,我实际上使用 DyanamoDB 流来创建到 S3 存储桶的投影,然后以这种方式进行大型导出。它甚至可能比您引用的 RethinkDB 导出更快。

简而言之,DynamoDb 最适合作为已知查询的事务键值存储。

【讨论】:

  • 如果您知道任何好的教程,我会对更深入的解释感兴趣。 :) 另外,我想知道您所说的“大型数据集”是什么意思。对我来说,5MB 根本不是“大型数据集”。
  • 对于任何对更深入的解释感兴趣的人,我们在 Slack 上进行了广泛的讨论serverless-contrib.slack.com/archives/CA4QT5VU3/…
【解决方案2】:

我在我的应用程序中遇到了完全相同的问题(即 DynamoDB 自动缩放对于按需的高强度工作来说不够快)。

当我能够解决这个问题时,我已经非常致力于 DynamoDB,所以我解决了这个问题。这就是我所做的。

当我即将开始一项高强度工作时,我以编程方式增加了我的 DynamoDB 表上的 RCU 和 WCU。在您的情况下,您可能有一个 lambda 来增加吞吐量,然后让该 lambda 启动另一个 lambda 来完成高强度工作。请注意,增加供应可能需要几秒钟,因此将其拆分为单独的 lambda 可能是个好主意。

我将在下面粘贴我遇到的问题的个人笔记。抱歉,但我懒得将它们格式化为 stackoverflow 标记。


我们希望始终提供足够的吞吐量,以便用户获得快速体验,更重要的是,不会出现任何失败的操作。但是,我们只想提供足够的吞吐量来满足我们的需求,因为这需要我们花钱。

在大多数情况下,我们可以在我们的表上使用 Autoscaling,它应该使我们预置的吞吐量适应实际消耗的量(即更多的用户 = 自动预置的更多吞吐量)。这对我们来说在两个关键方面失败了:

自动扩缩仅在超过吞吐量规定阈值后大约 10 分钟增加吞吐量。当它开始扩大规模时,这样做并不是很积极。这里有一个很棒的博客https://hackernoon.com/the-problems-with-dynamodb-auto-scaling-and-how-it-might-be-improved-a92029c8c10b。 当吞吐量消耗几乎为零时,DynamoDB 不会降低吞吐量。 AWS Dynamo not auto-scaling back down 我们真正需要管理吞吐量的地方是 Invoice 表 WCUs。 RCUs 比 WCUs 便宜很多,因此读取配置的担忧更少。对于大多数表,配置一些 RCU 和 WCU 应该足够了。但是,当我们从源中提取数据时,我们在 Invoices 表上的写入容量会持续 30 分钟。

假设我们只是依赖自动缩放。当用户开始提取时,我们将有 5 分钟的突发容量,这可能会或可能不会足够的吞吐量。自动缩放将在大约 10 分钟后启动(最多),但这样做会很笨重 - 不会像我们需要的那样快速扩展。我们的供应量不够高,我们会受到限制,我们将无法获得我们想要的数据。如果多个进程同时运行,这个问题会更加严重——我们无法同时处理多个数据提取。

幸运的是,我们知道何时要处理 Invoices 表,因此我们可以通过编程方式提高 Invoices 表的吞吐量。以编程方式增加吞吐量似乎很快就会生效。可能在几秒钟内。我在测试中注意到 DynamoDB 中的 Metrics 视图毫无用处。它的更新速度真的很慢,我认为有时它只是显示了错误的信息。您可以使用 AWS CLI 来描述该表,并实时查看预置的吞吐量:

aws dynamodb describe-table --table-name DEV_Invoices

理论上,我们可以在提取开始时增加吞吐量,然后在完成时再次减少。但是,虽然您可以随意增加吞吐量配置,但您一天只能减少 4 次吞吐量配置,尽管您可以每小时减少一次吞吐量(即 24 小时内减少 27 次)。 https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html#default-limits-throughput。这种方法行不通,因为我们减少供应很可能会失败。

即使 Autoscaling 发挥作用,它仍然必须遵守供应减少规则。因此,如果我们减少了 4 倍,自动缩放将不得不等待一个小时才能再次减少 - 这对于读取和写入值都是如此

以编程方式增加吞吐量供应是一个好主意,我们可以很快地做到这一点(比自动缩放快得多),因此它适用于我们不频繁的高工作负载。我们无法在提取后以编程方式降低吞吐量(见上文),但还有其他几个选项。

自动缩放以降低吞吐量

请注意,即使设置了自动缩放,我们也可以通过编程将其更改为我们喜欢的任何内容(例如,高于最大自动缩放级别)。

我们可以在提取完成后一两个小时内依靠 Autoscaling 将容量恢复,这不会花费我们太多。

还有另一个问题。如果在提取后我们消耗的容量下降到零,这很可能,没有消耗数据发送到 CloudWatch,并且 Autoscaling 不会做任何事情来减少预置容量,从而使我们停留在高容量上。

有两个软糖选项可以解决这个问题。首先,我们可以将最小和最大吞吐量设置设置为相同的值。因此,例如将 Autoscaling 中的最小和最大预置 RCU 设置为 20 将确保预置容量返回到 20,即使消耗的容量为零。我不知道为什么,但这有效(我已经测试过了,它确实有效),AWS 在这里承认解决方法:

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AutoScaling.html

另一个选项是创建一个 Lambda 函数来尝试每分钟对表执行一次(失败的)读取和删除操作。失败的操作仍然会消耗容量,这就是它起作用的原因。此作业可确保定期将数据发送到 CloudWatch,即使我们的“实际”消耗为零,因此自动缩放将正确减少容量。

请注意,读取和写入数据分别发送到 CloudWatch。因此,如果我们希望在实际消耗的 WCU 为零时减少 WCU,我们需要使用写入操作(即删除)。同样,我们需要一个读取操作来确保更新 RCU。请注意,读取失败(如果项目不存在)和删除失败(如果项目不存在)但仍会消耗吞吐量。

Lambda 用于降低吞吐量

在之前的解决方案中,我们使用 Lambda 函数不断“轮询”表,从而创建 CloudWatch 数据,使 DynamoDB Autoscaling 能够正常工作。作为替代方案,我们可以只使用一个定期运行的 lambda,并在需要时缩减吞吐量。当您“描述”一个 DynamoDB 表时,您将获得当前的预置吞吐量以及上次增加日期时间和上次减少日期时间。所以 lambda 可以说:如果预置的 WCU 超过阈值,并且我们最后一次增加吞吐量是半个多小时前(即我们不是在提取中间),那么让我们直接降低吞吐量。

鉴于这比自动缩放选项更多的代码,我不倾向于这样做。

【讨论】:

  • 感谢您提供非常有趣的反馈。既然我问了这个问题,我也尝试了类似的东西,基本上以编程方式将 RCU 增加到 300,但我不知道在考虑到它之前有延迟,我没​​有注意到任何改进。另外,我不知道通过自动缩放减少 RCU 的限制,不知道它有限制,例如每小时/每天可以执行的时间,我也指望自动缩放来减少 RCU并在不再需要它们时恢复正常状态。
  • 当您拥有 DynamoDB 表句柄时,您可以调用名为“wait”之类的函数,该函数会在更新其配置后等待表再次变为活动状态。如果您不调用 wait,您可以在配置更新生效之前开始使用该表。
  • 谢谢!为了测试这一点,我手动将 WCU 增加到 300(为了模拟动态增加),然后调用我的端点。好吧,它并没有更好地工作,尽管具有更高的读取容量单元,lambda 仍然超时。当有 300 个可用且无法及时回复时,它使用了大约 17 个 WCU。 drive.google.com/open?id=1lsaHRfF8_ZOEez6x2u5Inf-0PjuGOgxZ
  • 看起来您的进程不受 WCU 约束。你也增加了RCU吗?不太确定你的进程在做什么,但如果你的函数需要先读后写,你可能是 RCU 绑定的。
  • lambda 执行了一个扫描操作,它什么都不写,只是返回结果,我也将 RCU 增加到 300(该死的代价高昂,在 20-30 百万后将设置恢复正​​常尝试,每张桌子 300 RCU/WCU 大约是每月 180 美元)--EDIT-- 我在其他评论中提到了 WCU,但意思是 RCU,无论如何,正如解释的那样,我将两者都设置为 300 没有改进
猜你喜欢
  • 1970-01-01
  • 2017-05-27
  • 2016-01-25
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-14
  • 2021-06-03
相关资源
最近更新 更多