排查 Lambda 托管实例问题
节流和扩缩问题
纵向扩展过程中错误率高
问题:当流量迅速增加时,您会遇到节流错误(HTTP 429)。
原因:Lambda 托管实例根据 CPU 资源利用率和多并发饱和状态进行异步扩展。如果您的流量在 5 分钟内增长超过一倍,您可能会在 Lambda 纵向扩展实例和执行环境以满足需求时看到节流出现。
解决方案:
-
调整目标资源利用率:如果您的工作负载具有可预测的流量模式,则应设定较低的目标资源利用率,以便为流量突发留出更多的缓冲空间。
-
预热容量:对于计划中的流量增加,请通过较长时间的逐步增加来实现流量的提升,以使扩展保持同步。
-
监控扩展指标:跟踪节流错误指标,以了解节流和容量扩展问题的原因。
-
查看函数配置:确保您的函数内存和 vCPU 设置支持多并发执行。如果需要,请增加函数内存或 vCPU 分配。
减慢缩减
问题:流量减少后,实例的缩减过程会持续很长时间。
原因:Lambda 托管实例会逐渐缩减,以保持可用性并避免可能影响性能的快速容量变化。
解决方案:
这是预料之中的行为。Lambda 会谨慎地缩减实例,以确保稳定性。监控您的 CloudWatch 指标,以跟踪正在运行的实例数量。
并发问题
具有低并发性的执行环境会出现节流情况
问题:尽管有可用容量,但您的函数仍会出现节流情况。
原因:具有极低最大并发量的执行环境可能难以实现有效扩展。Lambda 托管实例专为多并发应用程序而设计。
解决方案:
-
提高最大并发数:如果您的函数调用所占用的 CPU 极少,可提高最大并发数设置至最高每个 vCPU 64 个。
-
优化函数代码:查看您的函数代码,以降低每次调用时的 CPU 使用量,从而实现更高的并发性。
-
调整函数内存和 vCPU:确保您的函数具备足够的资源来处理多个并发调用。
线程安全问题(Java 运行时)
问题:您的 Java 函数生成错误的结果或在负载下遭遇竞争条件。
原因:多个线程同时执行处理程序方法,且共享状态不具有线程安全性。
解决方案:
-
使用
AtomicInteger或AtomicLong替代基元类型作为计数器 -
将
HashMap替换为ConcurrentHashMap -
使用
Collections.synchronizedList()来包装ArrayList -
将
ThreadLocal用于特定于请求的状态 -
从 Lambda 上下文对象访问跟踪 ID,而不是环境变量
有关详细指导,请参阅 Lambda 托管实例的 Java 运行时文档。
状态隔离问题(Node.js 运行时)
问题:您的 Node.js 函数会从不同的请求中返回数据,或者会出现数据损坏的情况。
原因:全局变量在同一工作线程的并发调用中被共享。当异步操作释放控制权时,其他调用可以修改共享状态。
解决方案:
-
安装并将
@aws/lambda-invoke-store用于所有特定于请求的状态 -
将全局变量替换为
InvokeStore.set()和InvokeStore.get() -
在
/tmp中使用带有请求 ID 的唯一文件名 -
使用
InvokeStore.getXRayTraceId()访问跟踪 ID,而不是环境变量
有关详细指导,请参阅 Lambda 托管实例的 Node.js 运行时文档。
文件冲突(Python 运行时)
问题:您的 Python 函数从 /tmp 中的文件中读取了错误的数据。
原因:多个进程共享 /tmp 目录。对同一文件进行并发写入操作可能会导致数据损坏。
解决方案:
-
使用带有请求 ID 的唯一文件名:
/tmp/request_{context.request_id}.txt -
将文件锁定与
fcntl.flock()结合用于共享文件 -
在使用后通过
os.remove()清理临时文件
有关详细指导,请参阅 Lambda 托管实例的 Python 运行时文档。
性能问题
高内存利用率
问题:您的函数出现内存使用率过高或内存不足的问题。
原因:Python 中的每个并发请求都在单独的进程中运行,且拥有自己的内存空间。总内存使用量等于每个进程的内存占用量乘以并发进程数量。
解决方案:
-
在 CloudWatch 中监控
MemoryUtilization指标 -
如果内存使用量接近函数的内存限制,请降低
MaxConcurrency设置 -
增加函数内存分配以支持更高的并发数
-
通过按需加载数据而非在初始化时加载来优化内存使用情况
不一致的性能
问题:函数性能在不同的调用之间差异很大。
原因:Lambda 可能会根据可用性选择不同的实例类型,或者某些函数可能运行在资源可用性各不相同的实例上。
解决方案:
-
指定允许的实例类型:如果您有特定的性能要求,请在容量提供程序中配置允许的实例类型,以限制 Lambda 可选择的实例类型。
-
监控实例级别的指标:在容量提供程序级别进行跟踪
CPUUtilization和MemoryUtilization以确定资源限制。 -
查看容量指标:检查
vCPUAvailable和MemoryAvailable以确保您的实例上有足够的可用资源。
容量提供程序问题
函数版本未能变为 ACTIVE 状态
问题:您的函数版本发布后仍处于待处理状态。
原因:Lambda 正在启动托管实例并开启执行环境。此过程需要时间,特别是对于新容量提供程序上的第一个函数版本。
解决方案:
等待 Lambda 完成初始化过程。默认情况下,Lambda 会启动三个实例以实现可用区的容错功能,并在将您的函数版本标记为 ACTIVE 之前启动三个执行环境。这通常需要几分钟时间。
无法删除容量提供程序
问题:您在尝试删除容量提供程序时收到错误。
原因:您无法删除已附加了函数版本的容量提供程序。
解决方案:
-
使用
ListFunctionVersionsByCapacityProviderAPI 识别所有使用该容量提供程序的函数版本。 -
删除或更新这些函数版本,以解除容量提供程序的关联。
-
重新尝试删除容量提供程序。
发布函数过程中出现的一般错误消息
问题:发布函数时,您会遇到一般错误消息,例如“发布期间出现内部错误”。
解决方案:
-
检查 IAM 权限:确保您对尝试使用的容量提供程序拥有
lambda:PassCapacityProvider权限。 -
验证容量提供程序配置:使用
GetCapacityProviderAPI 确认您的容量提供程序处于 ACTIVE 状态。 -
查看 VPC 配置:确保您的容量提供程序中指定的子网和安全组配置正确且可访问。
-
检查 Amazon CloudTrail 日志:查看 CloudTrail 日志,了解有关失败操作的详细错误信息。
监控和可观测性问题
CloudWatch 指标缺失
问题:您在 CloudWatch 中无法看到您的容量提供程序或函数所对应的预期指标。
原因:这些指标每隔 5 分钟发布一次。新的容量提供程序或函数可能无法立即提供指标。
解决方案:
发布函数版本后,至少等待 5 到 10 分钟,然后才能期望在 CloudWatch 中看到相关指标。请确认您查看的命名空间(AWS/Lambda)和维度(CapacityProviderName、FunctionName 或 InstanceType)是否正确。
找不到 CloudWatch 日志
问题:您的函数成功执行,但在 CloudWatch Logs 中找不到相关日志。
原因:Lambda 托管实例在您的 VPC 中运行,需要网络连接才能将日志发送至 CloudWatch Logs。如果没有正确的 VPC 连接配置,您的函数将无法连接到 CloudWatch Logs 服务端点。
解决方案:
配置 VPC 连接来让您的函数将日志发送到 CloudWatch Logs。您有三种选择:
选项 1:CloudWatch Logs 的 VPC 端点(建议用于生产环境)
-
通过 console.aws.amazon.com/vpc/
打开 Amazon VPC 控制台。 -
在导航窗格中,选择端点。
-
选择 创建端点。
-
对于服务类别,选择 Amazon 服务。
-
在服务名称中,选择
com.amazonaws.region.logs(将region替换为您的 Amazon 区域)。 -
对于 VPC,请选择您的容量提供程序使用的 VPC。
-
对于子网,选择要在其中创建端点网络接口的子网。要获得高可用性,在多个可用区中选择子网。
-
对于安全组,请选择允许来自您函数安全组的入站 HTTPS 流量(端口 443)的安全组。
-
为端点启用私有 DNS。
-
选择创建端点。
选项 2:带有互联网网关的公有子网
如果您的容量提供程序使用公有子网,请确保:
-
互联网网关已连接到您的 VPC
-
路由表将
0.0.0.0/0流量路由到互联网网关 -
安全组允许端口 443 上的出站 HTTPS 流量
选项 3:具有 NAT 网关的私有子网
如果您的容量提供程序使用私有子网,请确保:
-
公有子网中存在 NAT 网关
-
私有子网路由表将
0.0.0.0/0流量路由到 NAT 网关 -
公有子网路由表将
0.0.0.0/0流量路由到互联网网关 -
安全组允许端口 443 上的出站 HTTPS 流量
有关 VPC 连接选项的详细指南,请参阅 Lambda 托管实例的 VPC 连接。
难以将来自并发请求的日志进行关联
问题:来自不同请求的日志是交错排列的,这使得难以跟踪具体的单个请求。
原因:在多并发系统中,日志的交错排列是预期且标准的行为。
解决方案:
-
使用采用 JSON 格式的结构化日志记录:在所有日志语句中包含请求 ID
-
Java:将 Log4j 与
ThreadContext配合使用以自动包含请求 ID -
Node.js:使用采用 JSON 格式的
console.log()并包含InvokeStore.getRequestId() -
Python:使用采用 JSON 格式的标准日志记录模块并包含
context.request_id
有关详细指导,请参阅特定于运行时的文档页面。
获得更多帮助
如果您在尝试这些解决方案后仍然遇到问题:
-
查看 CloudWatch 指标:检查容量提供程序和执行环境指标,以确定资源限制或扩展问题。
-
检查 Amazon CloudTrail 日志:查看 CloudTrail 日志,了解有关 API 调用和错误的详细错误信息。
-
联系 Amazon Support:如果您无法解决问题,请联系 Amazon Support,提供有关您的容量提供程序配置、函数配置以及您遇到的具体错误消息的详细信息。
后续步骤
-
使用 CloudWatch 指标监控 Lambda 托管实例