Lambda 递归循环检测 - Amazon Lambda
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

Lambda 递归循环检测

当您配置 Lambda 函数输出到调用该函数的同一服务或资源时,就可能会创建无限递归循环。例如,Lambda 函数可能会向 Amazon Simple Queue Service(Amazon SQS)队列写入一条消息,该队列随即调用同一函数。此调用导致该函数向队列写入另一条消息,而队列反过来再次调用该函数。

意外发生的递归循环可能会让您的 Amazon Web Services 账户 产生意外费用。循环还可能导致 Lambda 扩展并使用您账户的所有可用并发。为了帮助减轻意外循环的影响,Lambda 可以在某些类型的递归循环发生后不久将其检测出。在检测到递归循环时,Lambda 会停止调用函数并向您发送通知。

如果您的设计有意使用递归模式,则可以请求关闭 Lambda 递归循环检测。要请求进行此更改,请联系 Amazon Web Services Support

重要

如果您的设计有意使用 Lambda 函数将数据写回调用该函数的同一 Amazon 资源,则务必谨慎操作,并实施适当的防护措施,防止您的 Amazon Web Services 账户 产生意外费用。要了解使用递归调用模式的最佳实践的更多信息,请参阅 Serverless Land 中的 Recursive patterns that cause run-away Lambda functions

了解递归循环检测

Lambda 中的递归循环检测通过跟踪事件来工作。Lambda 是一种事件驱动型计算服务,可在某些事件发生时运行您的函数代码。例如,将项目添加到 Amazon SQS 队列或 Amazon Simple Notification Service(Amazon SNS)主题时,就会如此。Lambda 将事件作为 JSON 对象传递给您的函数,其中包含有关系统状态变化的信息。如果某一事件导致您的函数运行时,这就称为调用

为了检测递归循环,Lambda 会使用 Amazon X-Ray 跟踪标头。当支持递归循环检测的 Amazon Web Services 将事件发送到 Lambda 时,这些事件将自动使用元数据进行注释。当您的 Lambda 函数使用支持的 Amazon 开发工具包版本将其中一个事件写入另一个支持的 Amazon Web Service 时,就会更新此元数据。更新后的元数据包括事件调用该函数的次数计数。

注意

您无需启用 X-Ray 主动追踪,即可使用此功能。默认情况下,所有 Amazon 客户都启用递归循环检测。使用该功能不会产生任何费用。

请求链是由同一触发事件引起的一系列 Lambda 调用。例如,假设 Amazon SQS 队列调用了您的 Lambda 函数。然后,Lambda 函数将处理过的事件发送回同一 Amazon SQS 队列,该队列将再次调用您的函数。在此示例中,函数的每次调用都属于同一请求链。

如果您的函数在同一请求链中被调用的次数超过 16 次,则 Lambda 会自动停止该请求链中的下一次函数调用并向您发送通知。如果您的函数配置了多个触发器,来自其他触发器的调用则不会受到影响。

注意

当源队列的重新驱动策略的 maxReceiveCount 设置高于 16 时,Lambda 递归保护不会阻止 Amazon SQS 在检测到递归循环并终止后重试消息。当 Lambda 检测到递归循环并丢弃后续调用时,它会向事件源映射返回 RecursiveInvocationException。这会增加消息的 receiveCount 值。Lambda 会继续重试该消息,并继续阻止函数调用,直到 Amazon SQS 确定已超出 maxReceiveCount 并将消息发送到配置的死信队列。

如果您为函数配置了失败时的目标死信队列,则 Lambda 还会将已停止调用的事件发送到您的目标或死信队列。为函数配置目标或死信队列时,确保不要将函数也在使用的 Amazon SNS 主题或 Amazon SQS 队列,用作事件触发器或事件源映射。如果您将事件发送到调用函数的同一资源,则可以创建另一个递归循环。

受支持的 Amazon Web Services 和开发工具包

Lambda 只能检测包含某些受支持的 Amazon Web Services 的递归循环。为了检测到递归循环,您的函数还必须使用一种受支持的 Amazon 开发工具包。

支持 Amazon Web Services

Lambda 目前可检测您的函数、Amazon SQS 和 Amazon SNS 之间的递归循环。Lambda 还会检测仅由 Lambda 函数组成的循环,这些函数可以同步或异步地相互调用。下图显示了 Lambda 可以检测的一些循环示例:


          Lambda 函数、Amazon SNS 和 Amazon SQS 队列之间的递归循环图。

当 Amazon DynamoDB 或 Amazon Simple Storage Service(Amazon S3)等其他 Amazon Web Service 构成循环的一部分时,Lambda 目前无法对其进行检测和阻止。

由于 Lambda 目前仅检测涉及 Amazon SQS 和 Amazon SNS 的递归循环,因此涉及其他 Amazon Web Services 的循环仍有可能导致您的 Lambda 函数遭意外使用。

为防止 Amazon Web Services 账户 产生意外费用,我们建议您配置 Amazon CloudWatch 警报,提醒自己注意异常使用模式。例如,您可以将 CloudWatch 配置为在 Lambda 函数并发或调用出现峰值时向自己发送通知。您还可以配置账单警报,以便在账户中的支出超过指定的阈值时通知您。您也可以使用 Amazon Cost Anomaly Detection 来提醒自己注意异常的计费模式。

受支持的 Amazon 开发工具包

要让 Lambda 检测递归循环,您的函数必须使用以下开发工具包版本中的一种版本或更高版本:

运行时系统 所需 Amazon 开发工具包的最低版本

Node.js

2.1147.0(开发工具包版本 2)

3.105.0(开发工具包版本 3)

Python

1.24.46(boto3)

1.27.46(botocore)

Java 8 和 Java 11

1.12.200(开发工具包版本 1)

2.17.135(开发工具包版本 2)

Java 17

2.20.81

Java 21

2.21.24

.NET

3.7.293.0

Ruby

3.134.0

PHP

3.232.0

某些 Lambda 运行时系统(例如 Python 和 Node.js)包含 Amazon 开发工具包的一个版本。如果函数运行时系统中包含的开发工具包版本低于所需的最低版本,您可以将受支持的开发工具包版本添加到函数的部署包中。您还可以使用 Lambda 层将受支持的开发工具包版本添加到自己的函数中。有关每个 Lambda 运行时系统包含的开发工具包的列表,请参阅 Lambda 运行时

Lambda Go 运行时系统不支持 Lambda 递归检测。

递归循环通知

当 Lambda 停止递归循环时,您会通过 Amazon Health Dashboard 或电子邮件收到通知。您还可以使用 CloudWatch 指标来监控 Lambda 已停止的递归的调用次数。

Amazon Health Dashboard 通知

当 Lambda 停止递归调用时,Amazon Health Dashboard 会在账户运行状况页面的未决问题和近期问题下显示一条通知。请注意,在 Lambda 停止递归调用后,最多可能需要三个小时才能显示此通知。有关在 Amazon Health Dashboard 中查看账户事件的更多信息,请参阅《Amazon 运行状况用户指南》中的 Getting started with your Amazon Health Dashboard – Your account health

电子邮件警报

在首次停止函数的递归调用时,Lambda 会向您发送电子邮件警报。Lambda 每 24 小时最多为您 Amazon Web Services 账户 中的每个函数发送一封电子邮件。在 Lambda 发送电子邮件通知后,即使 Lambda 停止对该函数的进一步递归调用,您也不会在接下来的 24 小时内再收到该函数的更多电子邮件。请注意,在 Lambda 停止递归调用后,最多可能需要三个小时您才会收到此通知。

Lambda 会向您 Amazon Web Services 账户 的主要账户联系人和备用运营联系人发送递归循环电子邮件警报。有关查看或更新账户中电子邮件地址的信息,请参阅《Amazon 一般参考》中的 Updating contact information

Amazon CloudWatch 指标

CloudWatch 指标 RecursiveInvocationsDropped 会记录 Lambda 因您的函数在单个请求链中被调用次数超过 16 次而停止的函数调用次数。Lambda 会在停止递归调用后立即发出此指标。要查看此指标,请按照在 CloudWatch 控制台上查看指标的说明进行操作,然后选择指标 RecursiveInvocationsDropped

响应递归循环检测通知

当同一触发事件调用您的函数超过 16 次时,Lambda 会停止该事件的下一次函数调用,以便中断递归循环。为防止 Lambda 中断的递归循环再次出现,请执行以下操作:

  • 将函数的可用并发减少到零,即可限制未来发生的所有调用。

  • 移除或禁用会调用函数的触发器或事件源映射。

  • 识别并修复会将事件写回会调用函数的 Amazon 资源的代码缺陷。在使用变量定义函数的事件源和目标时,就会出现常见的缺陷来源。请检查并确认您为两个变量使用的是不同值。

此外,如果您的 Lambda 函数的事件源是 Amazon SQS 队列,则可以考虑在源队列上配置死信队列

注意

确保在源队列上配置死信队列,而不是在 Lambda 函数上配置。您在函数上配置的死信队列用于函数的异步调用队列,而不是用于事件源队列。

如果事件源是 Amazon SNS 主题,请考虑为您的函数添加失败时的目标

将函数的可用并发减少到零(控制台)
  1. 打开 Lamba 控制台的函数页面

  2. 选择函数的名称。

  3. 选择限制

  4. 限制函数对话框中,选择确认

删除函数的触发器或事件源映射(控制台)
  1. 打开 Lamba 控制台的函数页面

  2. 选择函数的名称。

  3. 选择配置选项卡,然后选择触发器

  4. 触发器下,选择要删除的触发器或事件源映射,然后选择删除

  5. 删除触发器对话框中,选择删除

禁用函数的事件源映射(Amazon CLI)
  1. 要找到要禁用的事件源映射的 UUID,请运行 Amazon Command Line Interface(Amazon CLI)list-event-source-mappings 命令。

    aws lambda list-event-source-mappings
  2. 要禁用事件源映射,请运行以下 Amazon CLI update-event-source-mapping 命令。

    aws lambda update-event-source-mapping --function-name MyFunction \ --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --no-enabled