amazon-web-services - 如何使用缓存的 boto3 客户端和 Lambda 预置并发刷新凭证?
问题描述
遵循最佳实践利用执行环境重用来提高函数的性能,我正在调查缓存boto3
客户端在使用 Lambda 预置并发时是否有任何负面影响。boto3
客户端通过装饰器缓存,并@lru_cache
进行延迟初始化。现在,需要担心的是boto3
客户端的基础凭据不会刷新,因为预配置并发将使执行环境在未知的时间内保持活动状态。此生命周期可能比 Lambda 环境注入的临时凭证的持续时间长。
我找不到任何解释如何处理此案的文档。有谁知道在上述情况下 Lambda 环境如何处理凭证的刷新?
解决方案
他们不是。
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今天的工作方式,未来可能会发生变化。但是改变是不可能的:当前的植入行为与记录的一样,任何改变都有破坏客户代码的风险。
推荐阅读
- python - 无法按名称找到元素
- dialogflow-es - 如何通过 V2 客户端库为节点 js 创建 OutPutContext
- python - 在 Selenium 网页中单击“显示更多交易”
- javascript - 具有 8 个不同值集的对象
- ruby-on-rails - Webpacker:启用监视模式或取消挂钩 webpacker:从资产编译:Rails 中的预编译任务?
- macos - 完全卸载protobuf
- css - Django 应用程序不加载 CSS 背景图像,但图像加载内联样式。有解决办法吗?
- apache-spark - 对于 HIVE 查询,Is OR 提供比 IN 更好的性能
- python - 按行和列在 matplotlib 中迭代生成子图 - 仅绘制最终轴
- google-app-engine - 无法将 VS2017 GCP 应用程序部署到谷歌云 App Engine