首页 > 解决方案 > 递归 AWS Lambda 函数调用 - 最佳实践

问题描述

我的任务是查看基于 AWS Lambda 构建的服务,该服务执行打开和关闭虚拟机的长期运行任务。请注意,我来自 Azure 团队,所以我不熟悉 AWS 服务的样式或最佳实践。

原始开发人员采用的方法是将整个工作负载发送到一个 Lambda 函数,然后让该函数占用一部分工作负载,然后使用剩余的工作负载递归调用自身,直到所有项目都消失(工作负载 = 0)。

伪代码:

// Assume this gets sent to a HTTP Lambda endpoint as a whole
let workload = [1, 2, 3, 4, 5, 6, 7, 8]

// The Lambda HTTP endpoint
function Lambda(workload) {
    if (!workload.length) {
        return "No more work!"
    }
    const toDo = workload.splice(0, 2) // get first two items
    doWork(toDo)

    // Then... except it builds a new HTTP request with aws sdk
    Lambda(workload) // 3, 4, 5, 6, 7, 8, etc.
}

这似乎非常低效且不可靠(如果我错了,请纠正我)。在这个过程中存储了很多状态,我认为这会产生很多故障点。

我的计划是建议我们重新设计整个服务以使用 Queue/Worker 类型的框架,理想情况下,端点一次处理一个工作负载,并且是无状态的。

队列将由一个服务填充(Jenkins?Lambda?手动?),然后第二个服务将从队列中读取(理想情况下也可以根据需要横向扩展)。

标签: amazon-web-servicesaws-lambda

解决方案


更新:AWS EventBridge 现在看起来像是首选解决方案。


我想到的是“耦合”,请参见此处:https ://www.jeffersonfrank.com/insights/aws-lambda-design-considerations

耦合
耦合超越了 Lambda 设计考虑——它更多的是关于整个系统。微服务中的 Lambda 有时是紧密耦合的,但只要在微服务的小黑匣子中的 Lambda 之间传递的数据不是过纯的 HTTP 并且不是同步的,这没什么好担心的。

Lambda 不应该以请求响应的方式直接相互耦合,而是异步耦合。考虑当 S3 事件调用 Lambda 函数时的场景,然后该 Lambda 还需要在同一微服务中调用另一个 Lambda,依此类推。

aws lambda 耦合

在此处输入图像描述

您可能很想实现直接耦合,例如允许 Lambda 1 使用 AWS 开发工具包调用 Lambda 2 等等。这引入了以下一些问题:

  1. 如果 Lambda 1 正在同步调用 Lambda 2,则需要等待后者先完成。Lambda 1 可能不知道 Lambda 2 也同步调用了 Lambda 3,而 Lambda 1 现在可能需要等待 Lambda 2 和 3 都成功完成。Lambda 1 可能会超时,因为它需要先等待所有 Lambda 完成,并且您还要在等待时为每个 Lambda 付费。
  1. 如果 Lambda 3 设置了并发限制并且也被另一个服务调用怎么办?Lambda 2 和 3 之间的调用将失败,直到它再次具有并发性。错误可以一直返回到 Lambda 1,但是 Lambda 1 然后如何处理错误?它必须存储 S3 事件不成功并且需要重播它。

这个过程可以重新设计为事件驱动:lambda 耦合

在此处输入图像描述

这不仅解决了直接耦合方法引入的所有问题,而且还提供了在每个 Lambda 发生错误时重放 DLQ 的方法。不会有消息丢失或需要外存,需求与处理解耦。


推荐阅读