在将现有的Node.js(Hapi.js)+ RethinkDB从OVH VPS(最小的vps)迁移到AWS Lambda(节点)+ DynamoDB的过程中,我最近遇到了一个非常大的性能问题。 / p>
用法非常简单,人们使用在线工具,并且“东西”通过node.js服务器/ lambda传递到数据库中。这个“东西”占用了一些空间,大约3kb(未压缩)(一个有很多键和子代的复杂对象,因此为什么使用NOSQL解决方案才有意义)
保存本身没有问题(目前...),没有多少人使用该工具,并且没有太多同步编写工作,因此使用Lambda而不是24/7有意义运行VPS。
真正的问题是我想下载那些结果。
因此,对于相同数量的提取数据,使用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,重新思考,postgre等)相比如此低的性能
我猜这一切都归结为正确的配置(那里可能还有很多要改进的地方),但是即使如此,为什么下载一大堆数据还是这么痛苦呢? 5MB没什么大不了的,但是如果感觉到它需要很多努力和关注,那只是导出单个表(统计信息,转储以进行备份等)的一种常见操作
编辑:自从我创建此问题以来,我读了https://hackernoon.com/the-problems-with-dynamodb-auto-scaling-and-how-it-might-be-improved-a92029c8c10b,它详细解释了我遇到的问题。基本上,自动缩放的触发速度缓慢,这说明了为什么我的用例无法正确缩放。如果您想了解DynamoDB自动缩放的工作原理,则必须阅读这篇文章。
答案 0 :(得分:1)
DynamoDB不适用于这种用法。它不像传统的数据库那样可以随心所欲地查询,特别是它不能同时处理大型数据集(例如您要的数据集)。
对于这种情况,我实际上使用DyanamoDB流在S3存储桶中创建投影,然后以这种方式进行大型导出。它甚至可能比您引用的RethinkDB导出更快。
简而言之,DynamoDb最适合作为已知查询的事务键值存储。
答案 1 :(得分:1)
我在应用程序中遇到了完全相同的问题(即,DynamoDB自动缩放无法以足够快的速度完成按需的高强度工作)。
当我能够解决问题时,我已经非常致力于DynamoDB了,所以我努力解决了这个问题。这就是我所做的。
当我要开始高强度工作时,我以编程方式增加了DynamoDB表上的RCU和WCU。在您的情况下,您可能需要一个lambda来增加吞吐量,然后让该lambda启动另一个来完成高强度工作。请注意,增加配置可能需要几秒钟,因此将其拆分为单独的lambda可能是一个好主意。
我将在下面遇到的问题上粘贴我的个人笔记。道歉,但我不介意将其格式化为stackoverflow标记。
我们希望一直提供足够的吞吐量,以使用户获得快速体验,更重要的是,不要让任何失败的操作。但是,我们只想提供足够的吞吐量来满足我们的需求,因为这会花费我们很多钱。
在大多数情况下,我们可以在表上使用自动缩放,这将使我们调配的吞吐量适应实际消耗的数量(即,更多的用户=自动调配更多的吞吐量)。对于我们而言,这在两个关键方面失败了:
自动缩放只会在吞吐量吞吐量阈值被突破后大约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 我们真正需要管理吞吐量的位置在“发票”表WCU上。 RCU比WCU便宜很多,因此读取数据时无需担心。对于大多数表,提供几个RCU和WCU应该足够了。但是,当从源中提取数据时,我们在“发票”表上的写入容量在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。这种方法行不通,因为我们减少供应可能会失败。
即使正在进行自动缩放,它仍必须遵守配置减少规则。因此,如果我们减小了4倍,那么自动缩放将不得不等待一个小时,然后才能再次减小-这就是读写值的全部
以编程方式增加吞吐量的提供是一个好主意,我们可以快速地做到这一点(比Autoscaling快得多),因此它可用于我们很少的高工作负载。提取后,我们无法通过编程方式降低吞吐量(请参见上文),但是还有两个其他选择。
自动缩放以减少吞吐量
请注意,即使设置了自动缩放功能,我们也可以通过编程方式将其更改为所需的值(例如,高于最大自动缩放级别)。
在提取完成后,我们可以依靠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,该lambda定期运行并在需要时按比例缩小吞吐量。当“描述” DynamoDB表时,您将获得当前的预配置吞吐量以及上次增加日期时间和上次减少日期时间。因此,lambda可以说:如果预配置的WCU超过阈值,并且上一次吞吐量增加是在半小时之前(即我们不在提取过程中),那么就让吞吐量立即降低。
鉴于此代码比“自动缩放”选项更多,因此我不愿意这样做。