上一节我们了解到,当Lambda第一次收到调用请求时,会初始化execution environment
,在这个阶段会下载函数代码(存放在AWS内部的S3桶中,如果使用镜像则从ECR中下载)、配置内存及函数运行时、运行handler外层代码。当完成这些准备工作后,才真正运行handler内部的代码:
上图中,前两个阶段(下载代码、准备Execution environment
)又统称为冷启动阶段
。这个阶段虽然不会额外收费,但却为我们的函数执行带来了整体延迟。在第一次执行完后,Execution environment
会保存一段时间,在这段时间内如果有后续的调用,则直接运行handler代码。
AWS通过对各个客户的Lambda调用模式进行统计,发现冷启动
才占不到1%,冷启动所花时间也不尽相同,从100ms以下到大于1s都有。并且一般线上业务请求量较频繁,冷启动发生的概率更低;测试环境和开发环境发生概率相对较高。
虽然说Lambda在第一次执行后,会保存execution environment
, 但还有很多场景会触发冷启动:
Lambda为了保证高可用,在各个AZ都会运行,并且根据流量向这些AZ进行负载均衡。假设某一时刻Lambda在很短时间内被调用两次,那么这两次运行都有可能经历冷启动,因为它们被负载到两个AZ运行了…
如果流量突增,Lambda会自动扩容,新扩容的函数也要初始化execution environment
,所以都要再经历冷启动的过程。 例如同时并发调用6次Lambda,每个调用都要新初始化执行环境:
每次更新Lambda函数代码或者更新它的配置,下一次调用时都会重新进行冷启动过程:
为了尽量减少冷启动,一些人想出了定时调用Lambda的方式,例如通过EventBridge
每隔一分钟调用一次Lambda来进行预热。不得不说,这种方式减少了执行Lambda时发生冷启动的概率,但由于负载均衡 + 自动扩容
机制的存在,依然不能保证不发生冷启动。
Provisioned Concurrency
是比较推荐的减少冷启动的方式。在调用Lambda之前,Provisioned Concurrency
帮我们完成了初始化的工作:
例如,如果我们为一个Lambda函数配置了6个Provisioned Concurrency
,那么当我们调用它之前,就提前准备好了6个execution environments
,避免调用时发生冷启动过程:
没有配置Provisioned Concurrency
的Lambda又叫on-demand
模式,和这种模式比起来,它有以下优点:
初始化代码
的时间。如果我们使用的runtime需要花费比较长的时间来进行初始化(例如Java),那么使用Provisioned Concurrency
能避免这段时间, 用户根本不用考虑对初始化代码进行优化。注意Provisioned Concurrency
不能在Lambda的 $LATEST
版本上使用