代码之家  ›  专栏  ›  技术社区  ›  Vadorequest

无服务器-dynamodb(糟糕的)性能与rethinkdb+aws lambda相比

  •  1
  • Vadorequest  · 技术社区  · 7 年前

    在将现有的node.js(hapi.js)+rethinkdb从ovh vps(最小的vps)迁移到aws lambda(node)+dynamodb的过程中,我最近遇到了一个非常大的性能问题。

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

    保存本身没有问题(目前…),没有那么多人使用该工具,也没有太多的同时写入操作,因此使用lambda而不是24/7运行vps是有意义的。


    真正的问题是我什么时候想下载这些结果。

    • 使用node+rethinkdb 小精灵 扫描整个表并生成要下载的csv文件
    • AWS Lambda+发电机 超时 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,但没有使用它们(我只是刚刚开始自动缩放,所以我想这是错误的配置?)

    cloudwatch

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

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


    所以,所有这些都让我想知道为什么dynamodb不能在30秒内完成,而reshightdb不能在3秒内完成,它与任何索引都没有关系,因为操作是一个“扫描”,因此必须以任何顺序遍历数据库中的所有项。

    我想知道我该如何获取那个巨大的数据集(5MB!)使用dynamodb生成csv。

    我真的很想知道dynamodb是不是适合这个工作的工具,我真的没想到与过去使用的工具(mongo、rethink、postgre等)相比,它的性能会这么低。

    我想这一切都取决于正确的配置(可能还有很多需要改进的地方),但即便如此,为什么下载一堆数据会这么痛苦?5MB不是什么大事,但如果感觉需要付出很大的努力和精力,而导出单个表(stats、dump for backup等)只是一个常见的操作。


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

    2 回复  |  直到 7 年前
        1
  •  1
  •   Gareth McCumskey    7 年前

    dynamodb不是为这种用途而设计的。它不像传统的数据库那样,你可以随心所欲地查询,尤其是在你请求的时候,它不能很好地处理大型数据集。

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

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

        2
  •  1
  •   F_SO_K    7 年前

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

    当我能够解决这个问题的时候,我已经非常投入到dynamodb中去了,所以我努力地解决了这个问题。这就是我所做的。

    当我准备开始一个高强度的工作时,我编程增加了dynamodb表上的rcu和wcu。在您的例子中,您可能有一个lambda来增加吞吐量,然后让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 我们真正需要管理吞吐量的地方是在发票表wcus上。RCU比WCU便宜得多,所以读操作不必担心。对于大多数表,提供一些RCU和WCU应该是足够的。然而,当我们从源代码中提取数据时,我们在发票表上的写容量在30分钟内很高。

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

    幸运的是,我们知道什么时候要猛攻invoices表,因此可以通过编程增加invoices表的吞吐量。以编程方式增加吞吐量似乎见效很快。可能几秒钟之内。我注意到在测试中,dynamodb中的metrics视图非常无用。更新速度真的很慢,我想有时候它只是显示了错误的信息。您可以使用aws cli来描述该表,并查看吞吐量的实时设置:

    aws dynamodb describe table——表名dev_invoices

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

    即使进行了自动缩放,它仍然必须遵守资源调配减少规则。因此,如果我们减少了4倍,自动缩放将需要等待一个小时才能再次减少-这是读和写的值

    以编程的方式增加吞吐量是一个好主意,我们可以很快(比自动缩放快得多)完成它,因此它适用于我们不经常出现的高工作负载。提取之后,我们无法通过编程降低吞吐量(见上文),但还有其他两个选项。

    自动缩放以减少吞吐量

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

    我们可以依靠自动缩放功能,在提取完成后一两个小时内将容量恢复到原来的水平,这不会花我们太多的钱。

    不过,还有一个问题。如果我们的消耗容量在提取之后下降到零,那么很可能没有消耗数据发送到cloudwatch,自动缩放也不会减少已调配的容量,从而使我们陷入高容量状态。

    不过,有两个软糖选项可以解决这个问题。首先,我们可以将最小和最大吞吐量设置为相同的值。因此,例如,将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能够自动调整功能。作为替代方案,我们可以使用lambda,它定期运行,并在需要时降低吞吐量。当您“描述”一个dynamodb表时,您将得到当前配置的吞吐量以及最后一次增加日期时间和最后一次减少日期时间。因此lambda可以说:如果提供的wcu超过了阈值,并且上次吞吐量增加的时间是半个多小时前(即,我们没有在提取过程中),那么让我们直接降低吞吐量。

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

    推荐文章