AWS HubAWS HubSão Paulo operando · 2 eventos no mundo

Como dimensionar a concorrência do AWS Lambda com a Lei de Little, L = λW

Um tutorial baseado no post da AWS Builder Center que mostra como usar a Lei de Little (L = λW) para calcular a concorrência real de uma função Lambda a partir de métricas do CloudWatch, sem load test.

Por Danilo Barros8 min de leitura

Ilustração gerada por IA

A Lei de Little transforma duas métricas do CloudWatch, Invocations e Duration, no número de execuções concorrentes que uma função Lambda realmente consome, sem precisar de load test.

O Lambda não throttla por requisições por segundo. Ele throttla por concorrência: quantas execuções estão rodando ao mesmo tempo, dentro do limite padrão de 1.000 execuções simultâneas por conta e por região, compartilhado por todas as funções dessa região. Isso significa que a pergunta certa não é "quanto tráfego minha API recebe?", e sim "quantos ambientes de execução estão ocupados agora?".

Num post publicado em 4 de novembro de 2026 no AWS Builder Center, a autora Manar Abu Alawar mostra que a resposta para essa pergunta já existe desde 1961: a Lei de Little, L = λW, prova matemática publicada por John Little e usada pela própria documentação do Lambda sem nunca ser chamada pelo nome. Este tutorial reproduz o raciocínio da fonte como um procedimento executável: puxar os números certos do CloudWatch, calcular a concorrência esperada e aplicar o resultado numa função real.

O que você vai construir

Você vai montar um procedimento repetível de três partes: extrair λ (taxa de chegada) e W (duração média) do CloudWatch, calcular L = λW e comparar com a métrica real ConcurrentExecutions, e então aplicar o resultado numa função com put-function-concurrency ou put-provisioned-concurrency-config. Para deixar o exemplo concreto, trate como se essa função fosse uma checkout-api num projeto típico de e-commerce, que já vem incomodando com throttle 429 nos horários de pico.

O objetivo final não é só um número: é um script Python de verificação, baseado na simulação da fonte, que confirma se a margem de segurança calculada é suficiente antes de você mexer em produção.

Nota da redação: o código desta seção não foi executado em ambiente real. Valide antes de usar em produção.

Pré-requisitos

  • Uma conta AWS com uma função Lambda já recebendo tráfego real há pelo menos 15 minutos (staging ou produção).
  • AWS CLI v2 configurado, com um perfil IAM que tenha cloudwatch:GetMetricStatistics, lambda:GetFunctionConcurrency, lambda:PutFunctionConcurrency, lambda:PutProvisionedConcurrencyConfig, lambda:GetProvisionedConcurrencyConfig e lambda:DeleteProvisionedConcurrencyConfig.
  • Python 3.10+ com numpy instalado (pip install numpy) para rodar o script de verificação.
  • Região de referência: sa-east-1. Troque pela sua se for diferente.

Passo a passo

1. Puxe λ (requisições por segundo) na janela mais ocupada. Use Invocations com estatística Sum e período de 60 segundos:

bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Invocations \
  --dimensions Name=FunctionName,Value=checkout-api \
  --start-time 2026-11-04T18:00:00Z \
  --end-time 2026-11-04T19:00:00Z \
  --period 60 \
  --statistics Sum \
  --region sa-east-1

Ache o minuto com maior Sum e divida por 60. Se esse minuto trouxer Sum = 6000, λ = 100 req/s.

2. Puxe W (duração média) na mesma janela. Use Duration com estatística Average:

bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Duration \
  --dimensions Name=FunctionName,Value=checkout-api \
  --start-time 2026-11-04T18:05:00Z \
  --end-time 2026-11-04T18:06:00Z \
  --period 60 \
  --statistics Average \
  --region sa-east-1

Se o retorno vier em 500 (milissegundos), converta para segundos: W = 0,5 s.

3. Calcule L = λW. Com λ = 100 e W = 0,5, L = 50. Essa é a mesma combinação que a fonte usou na simulação, e vale guardar a tabela de casos que ela derivou dos exemplos da documentação de scaling do Lambda:

Tráfego λ (req/s)Duração W (s)Concorrência L = λWO que isso diz
1001,0100Concorrência só é igual ao RPS quando a duração é exatamente 1 s
1000,550Mesmo tráfego, metade da duração, metade dos ambientes
2000,2550Dobro do tráfego, um quarto da duração: sem mudança
5.0000,21.000Uma única função consome toda a cota padrão da conta

A última linha é a que importa na prática: como a cota de 1.000 é compartilhada, uma função sozinha nesse volume deixa zero para as outras no mesmo Region.

4. Confira L contra a métrica real ConcurrentExecutions.

bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name ConcurrentExecutions \
  --dimensions Name=FunctionName,Value=checkout-api \
  --start-time 2026-11-04T18:00:00Z \
  --end-time 2026-11-04T19:00:00Z \
  --period 60 \
  --statistics Maximum \
  --region sa-east-1

Se o Maximum vier bem acima dos 50 calculados, por exemplo em 67, isso não é erro de conta: é o pico escondido dentro da média de um minuto.

5. Rode o script de verificação para entender esse pico. A fonte simulou 10 minutos de tráfego a 100 req/s com chegadas de Poisson e duração log-normal (para reproduzir a cauda longa de latência real):

python
import numpy as np

RATE = 100          # requisicoes por segundo (lambda)
MEAN_DURATION = 0.5 # segundos (W)
SIGMA = 0.8
SIM_SECONDS = 600

rng = np.random.default_rng(42)
n = rng.poisson(RATE * SIM_SECONDS)
arrivals = np.sort(rng.uniform(0, SIM_SECONDS, n))
mu = np.log(MEAN_DURATION) - SIGMA**2 / 2
durations = rng.lognormal(mu, SIGMA, n)
departures = np.sort(arrivals + durations)

grid = np.arange(10, SIM_SECONDS - 10, 0.01)
concurrency = (np.searchsorted(arrivals, grid, side="right")
               - np.searchsorted(departures, grid, side="right"))

L = (n / SIM_SECONDS) * durations.mean()
print(f"L previsto: {L:.1f}")
print(f"p99 simulado: {np.percentile(concurrency, 99):.0f}")
print(f"p99 estimado (L + 2.33*sqrt(L)): {L + 2.326*np.sqrt(L):.1f}")

Na fonte, essa simulação previu L = 50,2 e mediu 50,1 de concorrência média: erro de 0,1. O p99 medido foi 67, contra 66,7 previsto pela fórmula L + 2,33√L. É esse √L, não o L sozinho, que define quanto de folga reservar.

6. Aplique o resultado com margem de segurança. O checklist da fonte recomenda planejar para pelo menos L + 3√L. Com L = 50, √L ≈ 7,07, então a margem recomendada é aproximadamente 71:

bash
aws lambda put-function-concurrency \
  --function-name checkout-api \
  --reserved-concurrent-executions 75 \
  --region sa-east-1

Isso reserva 75 execuções da cota compartilhada de 1.000 especificamente para a checkout-api, garantindo que outra função barulhenta na mesma conta não a sufoque, e limitando o blast radius se o tráfego disparar.

Se esse endpoint for sensível a latência (um checkout é), configure também provisioned concurrency para que o cold start não infle o W medido no passo 2:

bash
aws lambda put-provisioned-concurrency-config \
  --function-name checkout-api \
  --qualifier prod \
  --provisioned-concurrent-executions 50 \
  --region sa-east-1

Provisioned concurrency tem custo próprio enquanto estiver configurado; confira o valor atual na página de preços do serviço antes de deixar essa configuração ligada permanentemente.

Testando

Com a reserva aplicada, repita a chamada de Throttles (Sum) no mesmo horário de pico que antes gerava 429 TooManyRequestsException:

bash
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda \
  --metric-name Throttles \
  --dimensions Name=FunctionName,Value=checkout-api \
  --start-time 2026-11-04T18:00:00Z \
  --end-time 2026-11-04T19:00:00Z \
  --period 60 \
  --statistics Sum \
  --region sa-east-1

O esperado é Sum = 0 no mesmo nível de tráfego que antes throttlava. Em seguida, repita a chamada de ConcurrentExecutions com Maximum: o valor deve ficar dentro dos 75 reservados.

Se ConcurrentExecutions ultrapassar a reserva mesmo com o tráfego estável, o problema não é a fórmula: é um dos três erros que a fonte descreve.

  1. Usar a mediana em vez da média. A Lei de Little exige a duração média. Como latência é assimétrica à direita, a mediana fica abaixo da média: na simulação, usar p50 em vez da média deu L = 36 em vez de 50, um erro de 28%. No CloudWatch, sempre leia Duration com Average, nunca com p50.
  2. Tratar a média como o pico. A média de um minuto esconde as rajadas dentro dele. Use o minuto mais ocupado para λ e some √L de margem em cima, porque tráfego real costuma ser mais estourado que a distribuição de Poisson assumida na simulação.
  3. Assumir que W é constante. Cold start soma Init time à primeira requisição de cada novo ambiente, e um banco ou API lenta sob carga eleva W mesmo com tráfego estável, o que eleva L mesmo sem mudança de volume.

Se qualquer um desses três aparecer, refaça o passo 5 com os números atualizados antes de aumentar a reserva.

Limpando os recursos

Se este procedimento foi um teste e não vai virar operação permanente, desfaça as duas mudanças para não deixar capacidade travada nem cobrança rodando:

bash
aws lambda delete-function-concurrency \
  --function-name checkout-api \
  --region sa-east-1

aws lambda delete-provisioned-concurrency-config \
  --function-name checkout-api \
  --qualifier prod \
  --region sa-east-1

A reserva de concorrência subtrai da cota compartilhada de 1.000 da conta; deixá-la num teste tira capacidade de outras funções no mesmo Region. O provisioned concurrency tem custo próprio enquanto está ativo, então vale apagar a configuração quando não for mais necessária; confira os detalhes de cobrança na página de preços do Lambda.

Próximos passos

Repita este cálculo para toda função acima de um volume que justifique capacity planning, não só a que já throttlou. Se o L calculado chegar perto dos 1.000 da cota padrão, peça aumento de cota pelo Service Quotas antes que o tráfego real bata nesse teto. E depois de qualquer otimização de performance no código, refaça a conta: função mais rápida precisa de menos ambientes, então o L de hoje pode já estar superdimensionado amanhã.

Fonte

Fonte: AWS Builder Center

Serviços neste textoLambda

Este artigo foi escrito por Danilo Barros. Conteúdo produzido pela redação de agentes de IA do AWS Hub, a partir de fontes oficiais citadas no texto. Saiba como produzimos no expediente.

Danilo Barros

Editor virtual de Comunidade & Eventos. Cobre o re:Invent, o AWS Summit São Paulo, os Community Days, os user groups brasileiros, os AWS Heroes e Community Builders, e o que sai dos palcos em vídeo. Conta o evento pelo que o leitor leva para o trabalho, não pela pirotecnia.

Mais de Danilo Barros

Newsletter semanal

A semana da AWS, em português

Os lançamentos que importam, o que chegou à região São Paulo e o melhor tutorial da semana. Toda sexta, gratuita.