为 亚马逊云科技 Lambda 异步调用实现错误处理

作者: 埃里克·约翰逊 |

本博客由战略客户高级解决方案架构师 Poornima Chand 和无服务器高级解决方案架构师 Giedrius Praspaliauskas 撰写。

亚马逊云科技 L ambda 函数允许同步和异步调用,两者都有不同的函数行为和错误处理方式:

当您同步调用函数时,Lambda 会将函数代码中所有未处理的错误返回给调用者。然后,调用者可以决定如何处理错误。使用异步调用时,调用者无需等待函数代码的响应。它将事件移交给 Lambda 服务来处理该进程。

由于调用者看不到任何下游错误,因此异步调用的错误处理可能更具挑战性,必须在 Lambda 服务层实现。

这篇文章解释了错误行为以及处理 Lambda 异步调用中错误的方法,以构建可靠的无服务器应用程序。

概述

亚马逊 S3 、 亚马逊 SNS 和 亚马逊 EventBridge 等 亚马逊云科技 服务异步调用 L ambda 函数。当您异步调用函数时,Lambda 服务会将事件置于内部队列中并返回不带额外信息的成功响应。一个单独的进程从队列中读取事件并将其发送到函数。

您可以通过在代码中实现错误处理和使用 Lambda 服务提供的错误处理功能来配置 Lambda 函数处理错误的方式。下图描述了在异步调用中观察和处理错误的解决方案选项。

Architectural overview

架构概述

了解错误行为

调用函数时,可能会出现两种类型的错误。如果 Lambda 服务在函数收到请求之前拒绝请求,则会出现调用错误(限制和系统错误(400 系列和 500 系列))。当函数的代码或运行时返回错误(异常和超时)时,就会发生函数错误。如果 Lambda 服务在异步调用中遇到未处理的错误,则会重试函数调用。

调用错误和函数错误的重试行为不同。对于函数错误,Lambda 服务默认重试两次,这些额外调用会产生费用。对于节流和系统错误,该服务将事件返回到事件队列,并尝试使用指数退避再次运行该函数长达 6 个小时。您可以通过设置事件的最大时限(最多 6 小时)和重试次数(0、1 或 2)来控制默认重试行为。这允许您限制重试次数并避免重试过时的事件。

处理错误

根据错误类型和行为,您可以使用以下选项在 Lambda 异步调用中实现错误处理。

Lambda 函数代码

处理错误的最典型方法是直接在函数代码中解决故障。虽然这种方法的实现因编程语言而异,但它通常涉及在 代码中使用 try/catch 块。

代码中的错误处理可能无法涵盖调用期间可能发生的所有潜在错误。如果您抑制错误,它还可能影响 CloudWatch 中的 Lambda 错误指标。您可以使用 Lambda 提供的错误处理功能来解决这些场景。

失败目的地

您可以将 Lambda 配置为使用 亚马逊云科技 Lambda Destination 向其他服务(例如 Amazon SQS、SNS 、Lambda 或 EventBridge)发送调用记录。 调用记录包含 JSON 格式的请求和响应的详细信息。您可以为成功处理的事件和所有处理尝试失败的事件配置单独的目的地。

对于失败目标,在用尽所有重试后,Lambda 会向目的地发送包含调用和错误详细信息的 JSON 文档。您可以使用此信息来确定重新处理策略(例如,扩展日志、单独的错误流、手动处理)。

例如,要在 亚马逊云科技 无服务器应用程序模型 ( 亚马逊云科技 SA M) 模板中使用 Lambda 目标:

ProcessOrderForShipping:
    Type: AWS::Serverless::Function
    Properties:
      Description: Function that processes order before shipping
      Handler: src/process_order_for_shipping.lambda_handler
      EventInvokeConfig:
        DestinationConfig:
          OnSuccess:
            Type: SQS
            Destination: !GetAtt ShipmentsJobsQueue.Arn 
          OnFailure:
            Type: Lambda
            Destination: !GetAtt ErrorHandlingFunction.Arn

死信队列

您可以使用 死信队列 (DLQ) 来捕获失败事件以进行重新处理。使用 DLQ,消息属性可以捕获错误详细信息。您可以将标准 SQS 队列或标准 SNS 主题配置为丢弃事件的死信队列。对于死信队列,Lambda 仅发送事件内容,不发送响应的详细信息。

这是在 亚马逊云科技 SAM 模板中使用死信队列的示例:

SendOrderToShipping:
    Type: AWS::Serverless::Function
    Properties:
      Description: Function that sends order to shipping
      Handler: src/send_order_to_shipping.lambda_handler
      DeadLetterQueue:
        Type: SQS
        TargetArn: !GetAtt OrderShippingFunctionDLQ.Arn 

设计注意事项

使用 DLQ 时有许多设计注意事项:

  • 函数代码中的错误处理可以很好地解决在代码中可以轻松解决的问题。例如,如果由于网络连接中断而出现故障,则重试数据库事务。
  • 需要复杂错误处理逻辑(例如,发送失败消息进行手动重新处理)的场景最好使用 Lambda 服务功能进行处理。这种方法将使函数代码更简单且易于维护。
  • 尽管死信队列的行为与失败时目标的行为相同,但死信队列是函数特定版本配置的一部分。
  • 发送到失败时目的地的调用记录比 DLQ 消息属性包含更多有关失败的信息。这包括故障条件、错误消息、堆栈跟踪、请求和响应负载。
  • Lambda 目的地还支持其他目标,例如其他 Lambda 函数和 EventBridge。这允许目的地为您提供对函数执行结果的更多可见性和控制权,并减少代码。

获得错误的可见性

对行为和错误的理解不能仅依赖错误处理。

你还想知道为什么错误会解决潜在的问题。您还必须知道错误率何时升高、错误的预期基准以及错误发生时系统中的其他活动。监控和可观察性,包括指标、日志和跟踪,可以让人们了解错误和潜在问题。

指标

当函数完成对事件的处理后,Lambda 会将有关该调用的指标发送到亚马逊 CloudWatch 。 这包括调用期间发生的错误的指标,你应该监控这些指标并做出反应:

  • 错误 — 导致函数错误的调用次数(包括您的代码和 Lambda 运行时都引发的异常)。
  • 限制 — 受限制的调用请求的数量(请注意,受限制的请求和其他调用错误在之前的指标中不算作错误)。

还有一些 针对异步调用 中错误的 指标

  • AsynceVentsDroped — 未成功运行函数而被丢弃的事件数量。
  • deadletterErrors — Lambda 尝试向死信队列 (DLQ) 发送事件但失败的次数(通常是因为资源配置错误或大小限制)。
  • DestinationDeliveryFailles — Lambda 尝试向目标发送事件但失败的次数(通常是由于权限、资源配置错误或大小限制)。

云观日志

Lambda 会自动向 亚马逊 CloudWatch Logs 发送日志。 您可以使用编程语言的标准日志记录功能写入这些日志。 生成的日志位于特定于您的函数的 CloudWatch Logs 组中,该组名为 /aws/lambda/。您可以使用 CloudWatch Logs Insight s 跨多个函数查询日志。

亚马逊云科技 X-Ray

亚马逊云科技 X-Ray 可以可视化应用程序的组件,识别性能瓶颈,并对导致错误的请求进行故障排除。请记住,亚马逊云科技 X-Ray 不会跟踪所有请求。采样率为每秒一个请求和额外请求的5%(这是不可配置的)。排除特定失败调用故障时,请勿将 亚马逊云科技 X-Ray 作为唯一工具,因为样本跟踪中可能缺少该工具。

结论

这篇博客文章介绍了使用各种方法在异步 Lambda 函数调用中进行错误处理,并讨论了如何获得对这些错误的可观测性。

有关所涵盖主题的更多详细信息,请访问:

  • 使用 Amazon SQS 死信队列重播消息
  • 介绍 亚马逊云科技 Lambda 目的地
  • 为 亚马逊云科技 Lambda 引入新的异步调用指标
  • 运营 Lambda:使用 CloudWatch 日志见解

如需更多无服务器学习资源,请访问 无服务器世界