如何使所需数量的 AWS Lambda 函数容器保持温暖

How to keep desired amount of AWS Lambda function containers warm

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

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

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

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

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

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

对于不了解冷启动的人,请阅读 this blog post 以更好地理解它。简而言之:

冷启动

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

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

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

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

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


解决方法:

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

话虽这么说,但这里详细介绍了如何同时为您的函数保持多个容器的温度:

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

  • 您的 Controller Lambda 函数 调用 Lambda 函数(您希望保持温暖的函数)并发 运行随心所欲地装容器。

这里有几点需要考虑:

  1. 您将必须构建并发,因为如果第一次调用 在另一个调用开始之前完成然后这个调用 可以重用以前的调用容器而不是创建新的 一。为此,您需要在 Lambda 函数,如果该函数由控制器调用 功能。 这可以通过将特定的有效负载传递给 具有这些调用的函数。你的 lambda 函数 want to be keep warm 将检查此有效负载是否存在。如果 它会执行然后函数将等待(以构建并发 调用),如果没有,则该函数可以执行为 预期。

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

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

我们正在使用 java(spring 引导)lambda,并且已经得出与 Kush Vyas 上面的答案几乎相同的解决方案,效果很好。

我们在负载测试中确实发现,在 "Controller function" 执行期间经常会出现合法的用户请求,再次导致不可避免的冷启动...

因此,现在在我们的 "Controller function" 中,我们有正常数量的 X 并发预热请求,但是每执行 5 次函数,我们就会额外调用目标 lambda 2 次。理论上我们最终会用 X+2 个 lambda 保持温暖,但是对于五分之四的预热调用,仍然会有 2 个冗余的 lambda 可以为用户请求提供服务。

它确实进一步减少了我们的冷启动次数(但显然还没有完全减少)并且我们仍在使用 concurrency/frequency 的 warm-ups/sleep-time 组合来为我们找到最佳解决方案 - 这些值将总是可能取决于特定情况下的负载要求。

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

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

你应该记住一件事 - 如果你的服务是 public 并且你关心 Google 洞察分数,你应该谨慎实施这种方法。

如果您使用 serverless framework with AWS Lambda, you can use this plugin 使所有 lambda 保持一定的并发水平。

AWS 刚刚宣布:

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

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