17

在我的项目中,有在 AWS API Gateway 和 AWS Lambda 上实现的 REST API。由于 AWS Lambda 函数在我们调用它时是无服务器且无状态的,因此 AWS 使用处理我们调用的 Lambda 函数代码启动一个容器。根据lambda 函数执行完成后的AWS 文档,AWS 不会停止容器,我们可以在该容器中处理下一个调用。这种方法提高了服务的性能——只有在第一次调用 AWS 时才花时间启动容器(Lambda 函数的冷启动),并且所有下一次调用的执行速度更快,因为它们使用相同的容器(热启动)。

作为提高性能的下一步,我们创建了 cron 作业,它定期调用我们的 Lambda 函数(为此我们使用 Cloudwatch 规则)。这种方法允许保持 Lambda 函数“温暖”,从而避免停止和重新启动容器。即当真正的用户调用我们的 REST API 时,Lambda 不会花时间来启动一个新的容器。

但是我们遇到了这个问题——这种方法只允许保温一个 Lambda 函数容器,而来自不同用户的实际并行调用数量可能要大得多(在我们的例子中是数百甚至数千个用户)。有什么方法可以为 Lambda 函数实现预热功能,它不仅可以加热单个容器,还可以加热一些所需数量的容器?

我知道这种方法会影响 Lambda 函数的使用成本,并且可能使用好的旧应用程序服务器会更好,但我认为这些方法及其成本的比较将是下一步,目前我只想找到加热所需数量的 Lambda 函数容器的方法。

4

5 回答 5

23

这可能会很长,但请耐心等待,因为这可能会为您提供解决方法,并且可能会让您更好地理解Lambda 的工作原理?

或者,如果您对阅读不感兴趣,您可以跳至底部解决方法”。

对于不了解冷启动的人,请阅读此博客文章以更好地理解它。简而言之:

冷启动

  • 当一个函数第一次执行或者在函数代码或资源配置更新之后,一个容器将被启动来执行这个函数。所有代码和库都将加载到容器中以使其能够执行。然后代码将运行,从初始化代码开始。初始化代码是在处理程序之外编写的代码。此代码仅在第一次创建容器时运行。最后,执行 Lambda 处理程序。这个设置过程被认为是冷启动。
  • 为了提高性能,Lambda 能够重用以前调用创建的容器。这将避免初始化新容器和加载代码。只有处理程序代码将被执行。但是,您不能依赖先前调用中的容器来重用。如果您没有更改代码并且没有太多时间过去,Lambda 可能会重用以前的容器。
  • 如果您更改了代码、资源配置或自上次调用以来已经过去了一段时间,则会初始化一个新容器,您将遇到冷启动。

现在考虑这些场景以便更好地理解:

  • 考虑第一次调用示例中的 Lambda 函数。Lambda 将创建一个容器,将代码加载到容器中并运行初始化代码。然后将执行函数处理程序。此调用将经历冷启动。正如评论中提到的,该功能需要 15 秒才能完成。一分钟后,再次调用该函数。Lambda 很可能会重新使用上一次调用中的容器。此调用不会经历冷启动。
  • 现在考虑第二种情况,第二次调用在第一次调用后 5 秒执行。由于前一个函数需要 15 秒才能完成并且尚未完成执行,因此新的调用将必须创建一个新容器才能执行此函数。因此,此调用将经历冷启动。

现在提出您已解决的问题的第一部分:

关于防止冷启动,这是一种可能,但不能保证,常见的解决方法只会保温 Lambda 函数的一个容器。为此,您将使用计划事件(cron 表达式)运行 CloudWatch 事件,该事件将每隔几分钟调用一次您的 Lambda 函数以使其保持温暖。


解决方法:

对于您的用例,您的 Lambda 函数将以非常高的并发率被非常频繁地调用。为避免尽可能多的冷启动,您将需要保持尽可能多的容器,以达到您期望的最高并发性。为此,您需要延迟调用函数以允许此函数的并发性构建并达到所需的并发执行量。这将迫使 Lambda 增加您想要的容器数量。因此,这会增加成本,并且不能保证避免冷启动。

话虽如此,这里是关于如何一次为您的函数保持多个容器温暖的分解:

  • 您应该有一个按计划触发的 CloudWatch Events 规则。此计划可以是固定速率或 cron 表达式。例如,您可以将此规则设置为每 5 分钟触发一次。然后,您将指定一个 Lambda 函数(控制器函数)作为此规则的目标。

  • 然后,您的控制器 Lambda 函数将为您希望的尽可能多的并发运行的容器调用 Lambda 函数(您想要保温的函数)。

这里有几点需要考虑:

  1. 您将必须构建并发性,因为如果第一次调用在另一个调用开始之前完成,那么这个调用可能会重用以前的调用容器而不是创建一个新的容器。为此,如果控制器函数调用了 Lambda 函数,则需要在该函数上添加某种延迟。这可以通过使用这些调用将特定的有效负载传递给函数来完成。然后,您想要保持温暖的 lambda 函数将检查此有效负载是否存在。如果是,则该函数将等待(以构建并发调用),如果不是,则该函数可以按预期执行。

  2. 如果您重复调用 Invoke Lambda API 调用,您还需要确保它不会受到限制。应编写您的 Lambda 函数来处理这种限制(如果发生),并考虑在 API 调用之间添加延迟以避免限制。

最后,此解决方案可以减少冷启动,但会增加成本,并且不能保证会发生冷启动,因为它们在使用 Lambda 时是不可避免的。如果您的应用程序需要更快的响应时间,那么使用 Lambda 冷启动会发生什么,我会建议考虑将您的服务器放在 EC2 实例上。

于 2018-07-11T17:44:38.130 回答
4

我们正在使用 java (spring boot) lambdas,并得出了与上面 Kush Vyas 的答案几乎相同的解决方案,效果很好。

然而,我们在负载测试期间确实发现,在“控制器功能”执行期间经常会出现合法的用户请求,再次导致不可避免的冷启动......

所以,现在在我们的“控制器函数”中,我们有常规数量的 X 个并发预热请求,但是每执行 5 次函数,我们就会额外调用 2 次目标 lambda。理论上,我们最终会得到 X+2 个 lambdas 来保持温暖,但是对于 5 个预热调用中的 4 个,仍然会有 2 个冗余 lambdas 可以服务用户请求。

它确实进一步减少了我们的冷启动次数(但显然仍不完全),我们仍在使用并发/热身频率/睡眠时间组合来为我们找到最佳解决方案——这些值可能总是取决于特定情况的负载要求。

于 2018-07-25T13:47:24.330 回答
3

AWS 刚刚宣布了这一点:

https://aws.amazon.com/about-aws/whats-new/2019/12/aws-lambda-announces-provisioned-concurrency/

请注意,虽然它不是免费的,而且对于我们保持 10 个 lambda 实例温暖的简单用例,我们的每日成本似乎将从 0.06 美元增加到 4 美元

于 2019-12-05T09:58:24.567 回答
1

如果您将无服务器框架与 AWS Lambda 一起使用,则可以使用此插件以一定程度的并发性保持所有 lambdas 温暖。

于 2019-01-20T17:31:21.973 回答
0

我想分享一些小而有用的技巧,我们用它来减少与冷启动相关的“用户观察到的”延迟。在我们的例子中,Lambda 函数通过 AWS API Gateway 处理来自前端的 HTTP 请求,特别是当用户在输入字段中键入内容时执行搜索功能。通常用户在 UI 呈现后开始输入会有一些延迟,所以我们有一些时间来执行对 Lambda 函数的 ping 调用以预热它。当用户向后端发出请求时,Lambda 很可能已经准备好工作了。

实际上,这种方法对于解决后端冷启动的问题没有任何作用,您需要寻找其他选项来解决它,但它可以在不费力气的情况下改善用户体验(类似于修补程序)。

您应该记住的一件事 - 如果您的服务是公开的并且您关心 Google Insights 分数,那么您应该小心实施这种方法。

于 2018-12-04T09:11:25.773 回答