了解 Lambda 托管实例执行环境
Lambda 托管实例提供了一种备选部署模式,即在客户自有的 Amazon EC2 实例上运行您的函数代码,而 Lambda 则负责管理相关运营事务。托管实例的执行环境与 Lambda(默认)函数存在多个重要差异,尤其是在处理并发调用和管理容器生命周期方面。
注意:有关 Lambda(默认)执行环境的信息,请参阅了解 Lambda 执行环境生命周期。
执行环境生命周期
Lambda 托管实例函数执行环境的生命周期与 Lambda(默认)在几个关键方面有所不同:
Init 阶段
在初始化阶段,Lambda 会执行以下步骤:
-
初始化并注册所有扩展程序
-
引导运行时入口点。运行时会启动所配置数量的运行时工作进程(实施取决于运行时)
-
运行函数初始化代码(处理程序之外的代码)
-
等待至少一个运行时工作进程通过调用
/runtime/invocation/next发出准备就绪信号
当扩展程序已初始化并且至少有一个运行时工作进程已调用 /runtime/invocation/next 时,初始化阶段即被视为已完成。然后,该函数即准备好处理调用。
注意
对于 Lambda 托管实例函数,初始化最长需要 15 分钟。超时时间为最大值 130 秒,或者为配置的函数超时时间(最长可达 900 秒)。
调用阶段
Lambda 托管实例函数的调用阶段具有几个独特的特征:
持续运行。与 Lambda(默认)不同的是,其执行环境始终处于持续运行状态,能够实时处理接收到的调用,而不会在每次调用之间出现停滞。
并行处理。在同一个执行环境中,可以同时进行多次调用,每项调用都会由不同的运行时工作进程来处理。
独立超时。该函数的配置超时适用于每次单独的调用。当一次调用超时后,Lambda 会将该特定调用标记为失败,但不会中断其他正在运行的调用或终止执行环境。
背压处理。如果所有运行时工作进程都在忙于处理调用,那么新的调用请求将会被拒绝,直到有工作进程可用为止。
错误处理和恢复
Lambda 托管实例函数执行环境中的错误处理与 Lambda(默认)不同:
运行时工作进程故障。如果某个运行时工作进程崩溃,执行环境会继续依靠其余正常运行的工作进程来维持运行。
扩展程序崩溃。如果扩展进程在初始化或操作期间崩溃,则整个执行环境将被标记为不正常并被终止。Lambda 会创建一个新的执行环境来替换它。
无法重置/修复。与 Lambda(默认)不同的是,托管实例不会在出错后尝试重置和重新初始化执行环境。相反,运行状况不佳的容器会被终止并由新的容器替代。
调用超时
当单个调用超时时,Lambda 会向调用方返回一个状态为函数错误的Task timed out after <timeout> seconds 的错误。但是,Lambda 托管实例不会强制终止您的代码——它会继续在执行环境中运行。作为函数开发人员,您负责检测和处理超时。上下文对象会暴露调用的剩余时间。零或负值表示调用已超时。执行环境中的其他并发调用继续正常处理。
重试行为
当调用超时时:
-
同步调用:调用方收到超时错误并负责重试。
-
异步调用:Lambda 根据函数的重试策略进行重试(默认:2 次重试)。所有重试用尽后,事件将被发送到配置的死信队列或失败目标(如果有)。
-
事件源映射:重试行为取决于事件源配置(例如,批次大小、出错时是否二分、最大重试次数)。根据您的重试策略,批次可能会被重试或发送到失败目标。
如果不处理超时会发生什么
如果您的代码不检查剩余时间并停止执行:
-
调用已被标记为失败。Lambda 已向调用方返回超时错误——您的代码在超时之后完成的任何工作实际上都已丢失(从调用方角度来看)。
-
资源仍被占用。您的代码会继续占用运行时工作线程槽位,从而减少该实例上可用于新调用的并发数。
-
非确定性行为。您的代码在超时触发时并不会停止——它会在后台继续运行。这意味着在 Lambda 已告知调用方调用失败之后,副作用仍可能发生。例如,您的处理程序向 DynamoDB 写入一条记录,然后超时触发,Lambda 向调用方返回超时错误,但您的代码仍在运行并继续发送 SNS 通知。调用方重试调用,这会再次写入记录并再次发送通知。您现在拥有重复数据和重复通知——并且无法轻松区分哪些来自仍在后台运行的“失败”调用。
在代码中处理超时
使用上下文对象检查剩余时间并在超时之前停止处理。根据下一工作单元的预期持续时间配置缓冲时间——例如,如果每个项目处理大约需要 500 毫秒,则将缓冲时间设置为至少 500 毫秒并留有余量。
有关超时处理的语言特定示例,请参阅每个运行时页面的请求上下文部分: