Lambda 函数扩展
并发是您的 Amazon Lambda 函数同时处理的正在进行的请求数。对于每个并发请求,Lambda 会预置单独的执行环境实例。当您的函数收到更多请求时,Lambda 会自动处理执行环境数量的扩展,直到您达到账户的并发限制。默认情况下,Lambda 为您的账户提供的单区域所有函数总并发上限为 1000。为了支持您的特定账户需求,您可以申请增加限额
本主题介绍了 Lambda 中的并发和函数横向缩减。在本主题结束时,您将能够了解如何计算并发、如何可视化两个主要的并发控制选项(预留类和预置类)、估计适当的并发控制设置,以及查看用于进一步优化的指标。
了解和可视化并发
Lambda 调用一个安全和隔离的执行环境中的函数。要处理请求,Lambda 必须先初始化执行环境(Init 阶段),然后再使用它来调用您的函数(Invoke 阶段):

注意
实际的 Init 和 Invoke 持续时间可能因多种因素而异,例如您选择的运行时和 Lambda 函数代码。前面的图的目的并不是表示 Init 和 Invoke 阶段持续时间的确切比例。
上图使用矩形表示单个执行环境。当函数收到其第一个请求(由带标签 1
的黄色圆圈表示)时,Lambda 会创建一个新的执行环境并在初始化阶段在主处理程序之外运行代码。然后,Lambda 在 Invoke 阶段运行函数的主处理程序代码。在整个过程中,此执行环境繁忙,无法处理其他请求。
当 Lambda 处理完第一个请求后,此执行环境就可以处理针对同一函数的其他请求。对于后续请求,Lambda 无需重新初始化环境。

在上图中,Lambda 重复使用执行环境来处理第二个请求(由带标签 2
的黄色圆圈表示)。
到目前为止,我们只关注您的执行环境的单个实例(即并发为 1)。实际上,Lambda 可能需要并行预置多个执行环境实例来处理所有传入请求。当您的函数收到新请求时,可能会发生以下两种情况之一:
-
如果预初始化的执行环境实例可用,Lambda 会使用它来处理请求。
-
否则,Lambda 会创建一个新的执行环境实例来处理请求。
例如,让我们来看看当您的函数收到 10 个请求时会发生什么:

在上图中,每个水平平面代表一个执行环境实例(标记为从 A
到 F
)。以下是 Lambda 处理每个请求的方式:
请求 1 到 10 的 Lambda 行为 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
请求 | Lambda 行为 | Reasoning | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 |
预置新环境 A |
这是第一个请求;没有可用的执行环境实例 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 |
预置新环境 B |
现有执行环境实例 A 繁忙 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3 |
预置新环境 C |
现有执行环境实例 A 和 B 都繁忙 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4 |
预置新环境 D |
现有执行环境实例 A、B 和 C 都繁忙 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5 |
预置新环境 E |
现有执行环境实例 A、B、C 和 D 都繁忙 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6 |
重用环境 A |
执行环境实例 A 已处理完请求 1,现已可用 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 |
重用环境 B |
执行环境实例 B 已处理完请求 2,现已可用 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
8 |
重用环境 C |
执行环境实例 C 已处理完请求 3,现已可用 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
9 |
预置新环境 F |
现有执行环境实例 A、B、C、D 和 E 都繁忙 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
10 |
重用环境 D |
执行环境实例 D 已处理完请求 4,现已可用 |
随着您的函数收到更多的并发请求,Lambda 会纵向扩展响应中的执行环境实例的数量。以下动画跟踪一段时间内的并发请求数:

通过将之前的动画冻结在六个不同的时间点,我们得到下图:

在上图中,我们可以在任何时间点绘制一条垂直线,并计算与该直线相交的环境数量。这为我们提供了该时间点的并发请求数。例如,时间 t1
处有 3 个处于活动状态的环境在处理 3 个并发请求。此模拟中的最大并发请求数发生在时间 t4
,此时有 6 个处于活动状态的环境处理 6 个并发请求。
总而言之,函数并发是它同时处理并发请求的数目。为了应对函数并发的增加,Lambda 预置了更多的执行环境实例以满足请求需求。
如何计算并发
通常,系统的并发是指同时处理多个任务的能力。在 Lambda 中,并发是您的函数同时处理的正在进行的请求数。一种衡量 Lambda 函数并发的快速而实用的方法是使用以下公式:
Concurrency = (average requests per second) * (average request duration in seconds)
并发不同于每秒的请求数。例如,假设您的函数平均每秒接收 100 个请求。如果平均请求持续时间为 1 秒,那么并发确实也是 100:
Concurrency = (100 requests/second) * (1 second/request) = 100
但是,如果平均请求持续时间为 500 毫秒,则并发为 50:
Concurrency = (100 requests/second) * (0.5 second/request) = 50
实际上,并发为 50 意味着什么? 如果平均请求持续时间为 500 毫秒,则可以将函数的实例视为每秒能够处理 2 个请求。然后,您的函数需要 50 个实例才能处理每秒 100 个请求的负载。并发为 50 意味着 Lambda 必须预置 50 个执行环境实例才能在没有任何节流的情况下高效处理此工作负载。以下是用方程式表示这种情况的方法:
Concurrency = (100 requests/second) / (2 requests/second) = 50
如果您的函数收到的请求数是原来的两倍(每秒 200 个请求),但只需要一半的时间来处理每个请求(250 毫秒),则并发仍为 50:
Concurrency = (200 requests/second) * (0.25 second/request) = 50
假设您有一个平均运行时间为 20 毫秒的函数。在峰值负载期间,可每秒观察 5000 个异步请求。在峰值负载期间,您的函数的并发是多少?
函数的平均持续时间为 20 毫秒或 0.020 秒。使用并发公式,您可以插入数字以获取 100 的并发:
Concurrency = (5,000 requests/second) * (0.020 seconds/request) = 100
或者,函数平均持续时间为 20 毫秒意味着您的函数每秒可处理 50 个请求。要处理每秒 5000 个请求的工作负载,您需要 100 个执行环境实例。因此,并发为 100:
Concurrency = (5,000 requests/second) / (50 requests/second) = 100
预留并发和预置并发。
默认情况下,您的账户有某个区域内的所有函数的并发上限,该上限为 1000。您的函数按需共享这个拥有 1000 个并发的并发池。如果您用尽了可用的并发,您的函数将节流(即它开始丢弃请求)。
您的某些函数可能比其他函数更重要。因此,您可能需要配置并发设置,以确保关键函数获得所需的并发。有两种并发控制:预留并发和预置并发。
-
使用预留并发可为函数预留账户并发的某部分。如果您不想让其他函数占用所有可用的非预留并发,这非常有用。
-
使用预置并发为一个函数预先初始化多个环境实例。这对于减少冷启动延迟很有用。
预留并发
若想保证您的函数在任何时候都有一定数量的并发可用,请使用预留并发。
预留并发是您要分配给函数的最大并发实例数。当将预留并发提供给函数时,任何其他函数都不可以使用该并发。换言之,设置预留并发会影响可用于其他函数的并发池。没有预留并发的函数共享剩余的非预留并发池。
配置预留并发将计入您的账户总并发上限。为函数配置预留并发不收取任何费用。
为了更好地理解预留并发,请细看下图:

在此图中,此区域中的所有函数的账户并发限制为默认限制 1000。假设您有两个关键函数 function-blue
和 function-orange
,它们通常会预估获得很高的调用量。您决定将 400 个单位的预留并发分配给 function-blue
,将 400 个单位的预留并发分配给 function-orange
。在此示例中,您账户中的所有其他函数必须共享剩余的 200 个单位的非预留并发。
该图有 5 个兴趣点:
-
在
t1
,function-orange
和function-blue
都开始接收请求。每个函数开始用完预留并发单位的分配部分。 -
在
t2
,function-orange
和function-blue
正在稳步接收更多请求。同时,您部署了某些其他 Lambda 函数,这些函数开始接收请求。您不将预留并发分配给这些其他函数。它们开始使用剩余的 200 个单位的非预留并发。 -
在
t3
,function-orange
达到最大并发 400。尽管您的账户中的其他地方有未使用的并发,但function-orange
无法访问它。红线表示function-orange
处于节流状态,Lambda 可能会丢弃请求。 -
在
t4
,function-orange
开始接收更少的请求并且不再节流。但是,您的其他函数会遇到流量峰值并开始节流。尽管您的账户中的其他地方有未使用的并发,但其他函数无法访问它。红线表示您的其他函数处于节流状态。 -
在
t5
,其他函数开始接收更少的请求并且不再节流。
在此示例中,请注意,预留并发具有以下效果:
-
您的函数可以独立于账户中的其他函数进行扩缩。在没有预留并发的同一区域中,您所有账户的函数共享非预留并发池。如果没有预留并发,其他函数可能会耗尽所有您的可用的并发。从而导致关键函数无法根据需要进行纵向扩展。
-
您的函数不能无节制地扩缩。预留并发对您的函数的最大并发设置了上限。这意味着您的函数不能使用为其他函数预留的并发,也不能使用非预留池中的并发。您可以预留并发以防止您的函数使用您账户中的所有可用并发,或者防止下游资源过载。
-
您可能无法使用账户的所有可用并发。预留并发计入您的账户并发上限,但这也意味着其他函数无法使用这一大部分预留并发。如果您的函数没有用完您为它预留的所有并发,那么您实际上是在浪费这个并发。除非您账户中的其他函数可以从浪费的并发中受益,否则这不是问题。
要管理函数的预留并发设置,请参阅 配置预留并发。
预配置并发
您可以使用预留并发来定义为 Lambda 函数预留的最大执行环境数。但是,这些环境都不会进行预先初始化。因此,您的函数调用可能需要更长的时间,因为 Lambda 必须先初始化新环境,然后才能使用它来调用您的函数。当初始化花费的时间超过预期时,这称为冷启动。为了减少冷启动,您可以使用预置并发。
预置并发是您要分配给函数的预初始化执行环境的数量。如果您在函数上设置预置并发,Lambda 会初始化该执行环境数量,以便它们准备好立即响应函数请求。
当使用预置并发时,Lambda 仍会在后台回收执行环境。但是,在任何给定时间,Lambda 始终确保预初始化环境的数量等于您的函数预置并发设置的值。这种行为与预留并发不同,在预留并发中,Lambda 可能会在不活动时段后完全终止环境。当您使用预留并发而不是预置并发来配置函数时,下图通过比较单个执行环境的生命周期来说明这一点。

该图有四个兴趣点:
Time | 预留并发 | 预配置并发 |
---|---|---|
t1 |
什么都未发生。 |
Lambda 预初始化一个执行环境实例。 |
t2 |
请求 1 传入。Lambda 必须初始化一个新的执行环境实例。 |
请求 1 传入。Lambda 使用预初始化的环境实例。 |
t3 |
在经过一段时间的不活动状态后,Lambda 会终止处于活动状态的环境实例。 |
什么都未发生。 |
t4 |
请求 2 传入。Lambda 必须初始化一个新的执行环境实例。 |
请求 2 传入。Lambda 使用预初始化的环境实例。 |
为了更好地了解预置并发,请细看下图:

在此图中,您的账户并发限制为 1,000。您决定将 400 个单位的预置并发量分配给 function-orange
。您账户中的所有函数,包括 function-orange
,都可以使用剩余的 600 个单位的非预留并发。
该图有 5 个兴趣点:
-
在
t1
,function-orange
开始接收请求。由于 Lambda 已经预先初始化 400 个执行环境实例,function-orange
可以立即调用。 -
在
t2
,function-orange
达到 400 个并发请求。因此,function-orange
已用尽预置并发。但是,由于仍有非预留并发可用,Lambda 可以使用它来处理对function-orange
的额外请求(没有节流)。Lambda 必须创建新实例来处理这些请求,并且您的函数可能会遇到冷启动延迟。 -
在
t3
,function-orange
在短暂的流量峰值后返回 400 个并发请求。Lambda 能够再次在没有冷启动延迟的情况下处理所有请求。 -
在
t4
,您账户中的函数会遇到流量突增的情况。这种突增可能产生于function-orange
或您账户中的任何其他函数。Lambda 使用非预留并发来处理这些请求。 -
在
t5
,您的账户中的函数达到 1,000 的最大并发上限,并且会节流。
前面的示例仅考虑了预置并发。实际上,您可以设置函数的预置并发和预留并发。如果您有一个函数可以处理恒定的调用负载,但是在周末经常出现流量峰值,那么您可以这样做。在这种情况下,您可以使用预置并发来设置基准环境数量以在工作日处理请求,并使用预留并发来处理周末的流量峰值。请细看以下图:

在此图中,假设您为 function-orange
配置了 200 个单位的预置并发和 400 个单位的预留并发。由于您配置了预留并发,因此 function-orange
无法使用 600 个单位的非预留并发中的任何一个。
该图有 5 个兴趣点:
-
在
t1
,function-orange
开始接收请求。由于 Lambda 已经预先初始化 200 个执行环境实例,function-orange
可以立即调用。 -
在
t2
,function-orange
已用尽其所有的预置并发。function-orange
可以继续使用预留并发来处理请求,但这些请求可能会遇到冷启动延迟。 -
在
t3
,function-orange
达到 400 个并发请求。因此,function-orange
已用尽其所有预留并发。由于function-orange
无法使用非预留并发,因此请求开始节流。 -
在
t4
,function-orange
开始接收更少的请求并且不再节流。 -
在
t5
,function-orange
降至 200 个并发请求,因此所有请求都能够再次使用预置并发(即没有冷启动延迟)。
预留并发和预置并发均计入您的账户并发限制和区域限额。换言之,分配预留和预置并发会影响可用于其他函数的并发池。配置预置并发会让您的 Amazon 账户产生费用。
注意
如果函数版本和别名上的预配置并发数加起来达到函数的预留并发,则所有调用都在预配置并发上运行。此配置还具有限制函数 ($LATEST
) 未发布版本的效果,从而阻止其执行。为函数分配的预配置并发数不能超过预留并发数。
要管理函数的预置并发设置,请参阅配置预置并发。要根据计划或应用程序利用率使预置并发扩缩自动化,请参阅使用 Application Auto Scaling 管理预置并发。
对比预留并发和预置并发。
下表总结并对比了预留并发和预置并发。
主题 | 预留并发 | 预配置并发 |
---|---|---|
定义 |
您的函数的最大执行环境实例数。 |
设置您的函数的预置执行环境实例数。 |
预置行为 |
Lambda 按需预置新实例。 |
Lambda 预置实例(即在您的函数开始接收请求之前)。 |
冷启动行为 |
由于 Lambda 必须按需创建新实例,因此可能出现冷启动延迟。 |
由于 Lambda 不必按需创建实例,因此冷启动延迟已消除。 |
节流行为 |
当达到预留并发限制时,函数会被节流。 |
如果未设置预留并发:当达到预置并发限制时,函数将使用非预留并发。 如果设置了预留并发:当达到预留并发限制时,函数会被节流。 |
如果未设置,则为默认行为 |
函数使用您的账户中可用的非预留并发。 |
Lambda 不预置任何实例。相反,如果没有设置预留并发:函数使用您的账户中可用的非预留并发。 如果设置了预留并发:函数使用预留并发。 |
定价 |
无额外费用。 |
会产生额外费用。 |
并发限额
对于可跨区域中所有函数使用的并发的总量,Lambda 可设置限额。这些限额分为两个级别:
-
在账户级别,默认情况下,您的函数最多可以有 1000 个单位的并发。要提高此限制,请参阅 Service Quotas User Guide(《服务限额用户指南》)中的 Requesting a quota increase(请求增加限额)。
-
在函数级别,默认情况下,您可以为所有函数保留最多 900 个单位的并发。对于未明确预留并发的函数,始终保留 100 个单位的并发。例如,如果您将账户并发限制提高到 2000,则可以在函数级别预留最多 1900 个单位的并发。
对于最初的流量突增,您的函数在一个区域中的累积并发可以达到 500 到 3000 之间的初始级别。
突增并发配额
-
3000 – 美国西部(俄勒冈)、美国东部(弗吉尼亚北部)、欧洲(爱尔兰)
-
1000 – 亚太地区(东京)、欧洲(法兰克福)、美国东部(俄亥俄)
-
500 – 其他区域
如果您的账户并发限制低于突增并发限制,Lambda 会根据您的账户并发来限制您的突增并发。例如,如果您的账户限制为 1000,则美国东部(弗吉尼亚州北部)的函数的突增并发为 1000。
在初始突增之后,您函数的并发可按每分钟增加 500 个实例的速度扩展。有关突增并发的更多信息,请参阅 突增并发。
准确估计所需并发
如果您的函数当前正在提供流量,则可以使用 CloudWatch 指标轻松查看其并发指标。具体而言,ConcurrentExecutions
指标显示了您账户中每个函数的并发调用数。

从图中可以看出,此函数平均处理 5 到 10 个并发请求,峰值通常为 20 个请求。假设您的账户中还有许多其他函数。如果此函数对您的应用程序至关重要,并且您不希望丢弃任何请求,则可以使用 20 作为预留并发设置。
请注意,您也可以使用以下公式计算并发:
Concurrency = (average requests per second) * (average request duration in seconds)
您可以使用 Invocation
指标估算每秒的平均请求数,并使用 Duration
指标估计平均请求持续时间(以秒为单位)。有关更多信息,请参阅 使用 Lambda 函数指标。
注意
如果您选择预置并发,Lambda 建议在您的函数通常需要的并发之外再包含一个 10% 的缓冲区。超额预置 10% 可确保您的函数始终能够使用预置并发处理传入请求,即使获得的流量略高于预期。例如,如果函数通常在出现 200 个并发请求时达到峰值,则可能需要将预置并发设置为 220(200 个并发请求 + 10% = 220 个预置并发)。
并发指标
您可以使用以下指标监控您的 Lambda 函数并发。
-
ConcurrentExecutions
– 当前处于活动状态的并发调用数。 -
UnreservedConcurrentExecutions
– 使用非预留并发的当前处于活动状态的并发调用数。 -
ProvisionedConcurrentExecutions
– 根据预置并发处理事件的执行环境实例的数目。对于具有预置并发性的别名或版本的每次调用,Lambda 都会发出当前计数。 -
ProvisionedConcurrencyInvocations
– Lambda 使用预置并发调用函数代码的次数。 -
ProvisionedConcurrencySpilloverInvocations
– 当所有预置并发均处于使用状态时,Lambda 根据标准(预留或非预留)并发调用函数代码的次数。 -
ProvisionedConcurrencyUtilization
– 对于版本或别名,为将ProvisionedConcurrentExecutions
值除以分配的预置并发总数。例如,.5 指明有 50% 的已分配预置并发正在使用中。