递归 AWS Lambda 函数调用 - 最佳实践

时间:2021-02-25 03:58:44

标签: amazon-web-services 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.
}

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

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

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

2 个答案:

答案 0 :(得分:2)

我想到的是“耦合”,请看这里:https://www.jeffersonfrank.com/insights/aws-lambda-design-considerations

<块引用>

耦合
耦合超出了 Lambda 的设计考虑——它更多地与整个系统有关。微服务中的 Lambda 有时是紧密耦合的,但只要 Lambda 之间在其微服务小黑盒中传递的数据不是过于纯粹的 HTTP 并且不是同步的,就无需担心。

<块引用>

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

aws lambda 耦合

enter image description here

<块引用>

您可能想要实现直接耦合,例如允许 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 耦合

enter image description here

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

答案 1 :(得分:2)

AWS Step Functions 是实现这一目标的一种方式。 Step Functions 用于以您想要的任何方式编排多个 Lambda 函数 - 并行执行、顺序执行或两者的混合。如果需要,您还可以放置等待步骤、条件检查、重试。

您的整体步骤函数可能看起来像这样(假设您希望并行执行 1、2、3。然后当所有这些都完成后,您希望并行执行 4,然后再次并行执行 5 和 6)

enter image description here

配置也很简单。它接受像下面这样的 JSON

{
  "Comment": "An example of the Amazon States Language using a parallel state to execute two branches at the same time.",
  "StartAt": "Parallel",
  "States": {
    "Parallel": {
      "Type": "Parallel",
      "Next": "Task4",
      "Branches": [
        {
          "StartAt": "Task1",
          "States": {
            "Task1": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:ap-south-1:XXX:function:XXX",
              "End": true
            }
          }
        },
        {
          "StartAt": "Task2",
          "States": {
            "Task2": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:ap-south-1:XXX:function:XXX",
              "End": true
            }
          }
        },
        {
          "StartAt": "Task3",
          "States": {
            "Task3": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:ap-south-1:XXX:function:XXX",
              "End": true
            }
          }
        }
      ]
    },
    "Task4": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-south-1:XXX:function:XXX",
      "Next": "Parallel2"
    },
    "Parallel2": {
      "Type": "Parallel",
      "Next": "Final State",
      "Branches": [
        {
          "StartAt": "Task5",
          "States": {
            "Task5": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:ap-south-1:XXX:function:XXX",
              "End": true
            }
          }
        },
        {
          "StartAt": "Task6",
          "States": {
            "Task6": {
              "Type": "Task",
              "Resource": "arn:aws:lambda:ap-south-1:XXX:function:XXX",
              "End": true
            }
          }
        }
      ]
    },
    "Final State": {
      "Type": "Pass",
      "End": true
    }
  }
}
相关问题