首页 > 解决方案 > 如何使用缓存的 boto3 客户端和 Lambda 预置并发刷新凭证?

问题描述

遵循最佳实践利用执行环境重用来提高函数的性能,我正在调查缓存boto3客户端在使用 Lambda 预置并发时是否有任何负面影响。boto3客户端通过装饰器缓存,并@lru_cache进行延迟初始化。现在,需要担心的是boto3客户端的基础凭据不会刷新,因为预配置并发将使执行环境在未知的时间内保持活动状态。此生命周期可能比 Lambda 环境注入的临时凭证的持续时间长。

我找不到任何解释如何处理此案的文档。有谁知道在上述情况下 Lambda 环境如何处理凭证的刷新?

标签: amazon-web-servicescachingaws-lambdaboto3credentials

解决方案


他们不是。

Boto3的文档没有很好地描述凭证链,但CLI 文档显示了凭证的各种来源(并且由于 CLI 是用 Python 编写的,因此它提供了权威文档)。

与从实例元数据中检索基于角色的凭证的 EC2 和 ECS 不同,Lambda 在环境变量中提供了凭证。Lambda 运行时在启动时设置这些环境变量,并且该 Lambda 运行时的每次调用都使用相同的值。

并发 Lambda 接收单独的凭证集,就像您对 STS 进行并发显式调用一样AssumeRole

预置并发有点棘手。您可能认为同一个 Lambda 运行时“永远存在”,但实际上并非如此:如果您反复调用具有预置并发性的 Lambda,您会看到它在某个时候会创建一个新的 CloudWatch 日志流。这表明 Lambda 已启动新的运行时。Lambda 将在停止向旧运行时发送请求之前完成新运行时的初始化,因此您不会遇到冷启动延迟。


更新:

这是一个 Python Lambda,它演示了我上面所说的内容。作为其初始化代码的一部分(在处理程序之外),它会记录首次初始化的时间,然后在调用时报告该时间戳。它还记录“AWS”环境变量的当前内容,以便您查看它们是否有任何变化。

import json
import os
from datetime import datetime

print("initializing environment")
init_timestamp = datetime.utcnow()

def lambda_handler(event, context):
    print(f"environment was initialized at {init_timestamp.isoformat()}")
    print("")
    print("**** env ****")
    keys = list(os.environ.keys())
    keys.sort()
    for k in keys:
        if k.startswith("AWS_"):
            print(f"{k}: {os.environ[k]}")

将其配置为预配置并发,然后使用此 shell 命令每 45 秒调用一次:

while true ; do date ; aws lambda invoke --function-name InvocationExplorer:2 --invocation-type Event --payload '{"foo": "irrelevant"}' /tmp/$$ ; sleep 45 ; done

让它运行一个小时或更长时间,您将获得两个日志流。第一个流看起来像这样(显示开始和结束,省略了数百条消息):

2021-10-19T16:19:32.699-04:00   initializing environment
2021-10-19T16:30:57.240-04:00   START RequestId: a27f6802-c7e6-4f70-b890-2e0172d46780 Version: 2
2021-10-19T16:30:57.243-04:00   environment was initialized at 2021-10-19T16:19:32.699455 
...
2021-10-19T17:07:24.853-04:00   END RequestId: dd9a356f-7928-4bf9-be56-86f4c5e1bb64
2021-10-19T17:07:24.853-04:00   REPORT RequestId: dd9a356f-7928-4bf9-be56-86f4c5e1bb64 Duration: 1.00 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 39 MB 

如您所见,Lambda 在 16:19:32 初始化,也就是我启用预置并发的时间。第一个请求在 16:30:57 处理。

但我要指出的是这个日志流中的最后一个请求,时间是 17:07:24,也就是 Lambda 初始化后大约 48 分钟。

第二个日志流是这样开始的:

2021-10-19T17:04:08.739-04:00   initializing environment
2021-10-19T17:08:10.276-04:00   START RequestId: 6b15ba7c-91e2-4f91-bb6c-99b9877f1ebf Version: 2
2021-10-19T17:08:10.279-04:00   environment was initialized at 2021-10-19T17:04:08.739398 

如您所见,它在第一个流中的最终请求前几分钟初始化,但在第一个流之后开始处理调用。

当然,这不是保证的行为。这就是 Lambda今天的工作方式,未来可能会发生变化。但是改变是不可能的:当前的植入行为与记录的一样,任何改变都有破坏客户代码的风险。


推荐阅读