O blog da AWS
Eliminando cold starts de Java com AWS Lambda Managed Instances
Por Jay Colodner, é TAM (US-SMB) na Amazon Web Services e Debasis Rath, GenAI Specialist SA na Amazon Web Services.
Um único cold start pode aumentar o tempo de resposta da sua função Lambda Java de milissegundos para segundos, o suficiente para violar seu SLA p99, causar timeout em um serviço downstream e acionar seu plantão. A Java Virtual Machine (JVM) tem melhor desempenho em processos de longa duração. Seu compilador Just-In-Time (JIT) otimiza progressivamente o código ao longo de milhares de invocações. Ambientes de execução Serverless padrão são reciclados antes que a JVM atinja o desempenho máximo. Isso cria um trade-off para aplicações sensíveis à latência entre penalidades de cold-start e otimizações de runtime. Para serviços de produção com requisitos de acordo de nível de serviço (SLA) p99, um único pico de cold start de 14 segundos pode violar garantias de tempo de resposta. Isso aciona timeouts downstream e degrada a experiência do cliente.
AWS Lambda Managed Instances muda essa equação. Como uma capacidade do AWS Lambda, Managed Instances executa suas funções em instâncias gerenciadas do Amazon Elastic Compute Cloud (Amazon EC2) na sua conta e mantém a persistência da JVM entre invocações. Pools de conexão, hierarquias de classes e estado de heap persistem ao longo de milhares de requisições. Isso permite que o compilador JIT C2 complete otimizações como inlining de métodos, análise de escape e desenrolamento de loops. O resultado: 18 a 30% melhor latência mediana e 3 a 30x melhor latência de cauda comparado ao Lambda padrão, como os benchmarks nesta publicação demonstram.
Esta publicação compara quatro modos de implantação Java em três tipos de carga de trabalho usando 240.000 requisições. Os modos comparados são Lambda padrão, AWS Lambda SnapStart, GraalVM Native Image e Lambda Managed Instances. Os tipos de carga de trabalho são limitados por CPU, I/O + computação e limitados por I/O. Esta publicação apresenta resultados de benchmark demonstrando Managed Instances entregando 30% melhor latência mediana e removendo picos de cold-start de múltiplos segundos em trabalho limitado por CPU após o aquecimento do JIT. Explica por que esses ganhos ocorrem, mapeia cada modo de implantação para padrões de tráfego específicos e requisitos de tolerância a cold-start, e fornece uma estrutura de decisão para selecionar a abordagem certa para sua carga de trabalho.
Configuração do benchmark
O benchmark executa todos os quatro modos de implantação com aplicações Spring Boot 4.0.6 idênticas em Java 25 e AWS SDK v2. Esta configuração verifica comparação justa entre os modos. Testamos três cargas de trabalho: UC1 (geração de PDF, limitado por CPU), UC2 (agregação de dados, I/O + computação) e UC3 (orquestração de API, limitado por I/O). O benchmark envia 240.000 requisições usando teste de carga Artillery a 33 RPS. Lambda padrão, SnapStart e Native Lambda usam 1024 MB (1 vCPU). Managed Instances usa instâncias c7i.xlarge com 2048 MB de memória. A concorrência é ajustada por carga de trabalho (UC1=3, UC2=5, UC3=10) com base em testes de carga para evitar contenção de threads. O benchmark mede latência p50, p99 e máxima em 10 execuções de 2.000 requisições cada, com intervalo de 5 minutos entre execuções. O benchmark rastreia métricas de compilação JIT via Amazon CloudWatch Embedded Metrics Format. Você pode validar esses resultados contra logs de acesso do Amazon API Gateway, que confirmam uma taxa de erro <0,1%. O repositório GitHub contém código-fonte completo, templates do AWS Serverless Application Model (AWS SAM), scripts de carga e dados brutos. Afirmações de desempenho nesta publicação referenciam dados desta metodologia de benchmark.
A Figura 1 apresenta a arquitetura para todos os quatro modos de implantação executando em paralelo contra serviços backend compartilhados.

Para reproduzir esses benchmarks ou implantar as aplicações de exemplo, consulte o repositório GitHub. O repositório contém templates SAM completos, configurações de carga Artillery, instruções de implantação e comandos de limpeza. Esta publicação foca em resultados e análise de benchmark. O benchmark usou as seguintes ferramentas e serviços:
- Uma conta AWS com permissões para criar funções Lambda, tabelas do Amazon DynamoDB, buckets do Amazon Simple Storage Service (Amazon S3), tópicos do Amazon Simple Notification Service (Amazon SNS) e filas do Amazon Simple Queue Service (Amazon SQS)
- Java 25 (Amazon Corretto recomendado).
- Maven 3.9+.
- AWS SAM CLI v1.155 ou posterior.
- Docker (para builds de imagem nativa GraalVM) ou alternativa.
- Artillery para teste de carga.
- O repositório GitHub com código-fonte completo e templates SAM
Observando latência máxima
Managed Instances remove os picos extremos de cauda característicos de cold starts. Managed Instances entrega latência máxima 27x mais rápida em cargas de trabalho limitadas por CPU (UC1: 489 ms vs. 13.270 ms padrão). Cargas de trabalho mistas de I/O + computação veem uma melhoria de 3x (UC2: 3.644 ms vs. 11.174 ms padrão). Cargas de trabalho limitadas por I/O melhoram 30x (UC3: 309 ms vs. 9.237 ms padrão). Medimos todos os resultados usando a metodologia descrita em Configuração do benchmark.

O máximo de 13 segundos do Lambda padrão em UC1 representa um cold start completo. Esse cold start inclui inicialização da JVM, inicialização do contexto Spring, configuração do cliente do Amazon DynamoDB e a primeira renderização de PDF. SnapStart reduz isso para menos de 3 segundos restaurando de um snapshot de Firecracker microVM. No entanto, o processo de restauração mais a reinicialização de recursos que não podem ser checkpointed (conexões de rede, geradores de números aleatórios) ainda adiciona latência. GraalVM Native inicia em menos de 2 segundos porque o binário compilado ahead-of-time (AOT) pula completamente a inicialização da JVM. O máximo de 487 ms do Managed Instances não é um cold start; é a requisição warm mais lenta em 20.000 invocações. Para SLAs de produção, um pico de cold start de 14 segundos no Lambda padrão viola a maioria dos requisitos, enquanto Managed Instances remove esse pico completamente.
Observando latência mediana (p50)
Lambda Managed Instances entregou a menor latência mediana em todas as três cargas de trabalho. Os resultados demonstram latência mediana 30% mais rápida em cargas de trabalho limitadas por CPU (UC1: 97 ms vs. 139 ms padrão). I/O misto + computação alcança uma melhoria de 19% (UC2: 184 ms vs. 228 ms padrão). Cargas de trabalho limitadas por I/O melhoram 18% (UC3: 76 ms vs. 93 ms padrão).

A melhoria escala com intensidade de CPU porque o compilador JIT C2 em Managed Instances persistentes otimiza caminhos de código quentes que ambientes Serverless de curta duração nunca alcançam. Em cargas de trabalho limitadas por CPU (UC1), o compilador JIT tem mais oportunidade de otimizar loops apertados na renderização de PDF. Em cargas de trabalho limitadas por I/O (UC3), a latência de rede para Amazon DynamoDB, Amazon SQS e Amazon SNS domina a duração da requisição, então a otimização JIT fornece ganhos menores.
Observando latência de cauda (p99)
Managed Instances mostrou melhorias ainda maiores na cauda da distribuição de latência. O p99 melhora 36% em cargas de trabalho limitadas por CPU (UC1: 225 ms vs. 353 ms padrão). I/O misto + computação alcança uma melhoria de 41% (UC2: 1.883 ms vs. 3.201 ms padrão). Cargas de trabalho limitadas por I/O melhoram 27% (UC3: 193 ms vs. 265 ms padrão).

UC2 mostrou a maior melhoria p99 (41%) porque a agregação de dados combina consultas DynamoDB, retornando centenas de registros com computação estatística em memória e uploads para Amazon S3. Ambientes Lambda padrão que não aqueceram completamente seu JIT produzem respostas significativamente mais lentas na cauda. A otimização JIT persistente (-Xms512m -Xmx1408m) com coleta de lixo (GC) G1 e dimensionamento explícito de heap em Managed Instances contribuem para uma distribuição de latência de cauda mais apertada. Para serviços com SLAs em tempo de resposta p99, essa melhoria de confiabilidade importa mais do que desempenho mediano. Para cargas de trabalho com pressão significativa de heap, ajustar -XX:MaxGCPauseMillis e monitorar logs de GC pode apertar ainda mais a latência de cauda.
Por que Lambda Managed Instances é mais rápido: compilação JIT
O compilador Just-In-Time da JVM funciona em camadas. O compilador C1 realiza compilação inicial rapidamente com otimizações básicas. O compilador C2 perfila a execução ao longo de centenas de invocações e então aplica otimizações agressivas: inlining de métodos (eliminando sobrecarga de chamadas de função), análise de escape (alocando objetos na pilha em vez do heap), desenrolamento de loops (reduzindo sobrecarga de ramificação) e vetorização (processando múltiplos elementos de dados em uma única instrução de CPU).
A tabela a seguir apresenta a progressão de aquecimento JIT usando java.lang.management.
CompilationMXBean emitido através do Amazon CloudWatch Embedded Metrics Format. Coletamos esses dados de um teste de carga sustentada de 1.500 requisições em UC1 (geração de PDF):
| Fase | Invocação | Latência Média | O Que Está Acontecendo |
| Primeiras requisições (inicialização da aplicação) | 1 | ~2.400ms | Inicialização da JVM, criação do contexto Spring, configuração do cliente SDK |
| Requisições iniciais (compilado C1) | 2-100 | ~145ms | Compilador C1 ativo. App é funcional, mas não otimizado |
| Estado estável (otimizado C2) | 1000+ | ~38ms | Otimizações C2 completadas |
A primeira invocação inclui custos únicos de inicialização da aplicação: carregamento de classes, inicialização do contexto Spring e construção do cliente DynamoDB. Esses custos não estão relacionados à compilação JIT e ocorrem em qualquer modo de implantação.
Uma vez que a compilação C1 se estabiliza durante as invocações iniciais, a latência atinge aproximadamente 145ms. Esta é a performance compilada de linha de base. Ao longo das próximas centenas de invocações, o compilador C2 perfila caminhos de código quentes e aplica otimizações. Na invocação 1.000, a latência cai para 38ms. Isso representa uma melhoria de 3,8x apenas da otimização JIT.
Ambientes Lambda padrão tipicamente reciclam antes que o C2 complete seus passes de otimização. Em Managed Instances, requisições concorrentes compartilham a mesma JVM. Isso acelera o perfilamento JIT: três requisições concorrentes geram três vezes os dados de invocação de método para o compilador C2 otimizar. O compilador C2 perfila padrões de execução em todas as requisições concorrentes. Ele identifica caminhos de código quentes mais rapidamente e aplica otimizações mais cedo do que ambientes de concorrência única.
O que isso significa: Cargas de trabalho limitadas por CPU veem os maiores ganhos (latência mediana 30% mais rápida em UC1) porque o compilador JIT tem mais oportunidade de otimizar loops apertados e chamadas de método. Cargas de trabalho limitadas por I/O veem ganhos menores (18% mais rápido em UC3) porque a latência de rede para DynamoDB, SQS e SNS domina a duração da requisição. O compilador JIT ainda otimiza seu código, mas o tempo de rede permanece constante em todos os modos de implantação.
Escolhendo o modo certo
Nenhum modo único vence em todos os cenários. A escolha certa depende do seu padrão de tráfego, tolerância a cold-start, expertise da equipe e orçamento de complexidade operacional.
Lambda Managed Instances é ideal para padrões de tráfego em estado estável acima de 5 requisições por segundo com baixa tolerância a cold-start (SLA p99 abaixo de 500 ms). Melhor para cargas de trabalho com tráfego previsível e sustentado que precisam de baixa latência com zero cold starts. Managed Instances se destaca em cargas de trabalho limitadas por CPU onde a otimização JIT se acumula.
SnapStart funciona bem para padrões de tráfego variável onde a redução de cold-start importa. Escolha isso como padrão para funções Lambda Java. SnapStart reduz cold starts com mudanças mínimas de código (adicionar priming CRaC). Você não tem infraestrutura adicional para gerenciar. Funciona com o modelo de escalonamento Lambda existente.
GraalVM Native Image funciona bem para padrões de tráfego intermitentes com tolerância estrita a cold-start (cold starts sub-segundo necessários). Ideal se sua equipe pode investir em compatibilidade AOT (configuração de reflexão, pipeline de build). Este modo oferece menor footprint de memória. Requer teste para compatibilidade de SDK.
Lambda padrão é a linha de base para cargas de trabalho de baixo tráfego ou intermitentes onde cold starts de 6-14 segundos são aceitáveis. Funciona bem quando a frequência de invocação é baixa o suficiente para que o faturamento por requisição seja mais barato do que custos de instância fixos, ou quando simplicidade operacional é a prioridade máxima.
Por exemplo, se você executa uma API Spring Boot lidando com 100 requisições por segundo com um SLA p99 de 400 ms, Lambda Managed Instances reduz seu p99 de 353 ms (cortando fino) para 225 ms (margem confortável) e remove os picos de cold start de múltiplos segundos que violam seu SLA completamente.
| Dimensão | Padrão | SnapStart | Native | Managed Instances |
| Cold start | 6-14 s | 2-7 s | 800 ms – 2 s | Nenhum |
| p50 warm (limitado por CPU) | 139 ms | 127 ms | 107 ms | 97 ms |
| Latência de cauda | Pior | Melhor | Bom | Mais rápido |
| Taxa de erro | Baixa | Baixa | Maior (compat SDK) | Baixa |
| Complexidade operacional | Mais baixa | Baixa | Alta (pipeline de build) | Média (VPC, dimensionamento) |
| Escalonamento de rajada | Mais rápido | Mais rápido | Mais rápido | Mais lento (capacity provider) |
| Esforço de migração | Nenhum | Baixo (adicionar priming CRaC) | Alto (compat AOT, configuração de reflexão) | Médio (capacity provider, VPC, thread safety) |
| Eficiência de memória | Boa | Boa |
Mais baixa (125-154 MB) |
Fixa por instância |
Lambda Managed Instances suporta instâncias Graviton4 (arm64), que oferecem aproximadamente 20% melhor relação preço-desempenho com base em benchmarks Graviton4 publicados pela AWS. Esses benchmarks usam x86_64 para consistência em todos os quatro modos (compilação cruzada nativa GraalVM para arm64 adiciona complexidade). As características de paralelização arm64 poderiam mudar as curvas de desempenho para modos de implantação de vida mais longa como Managed Instances de maneiras que vale a pena explorar em um post futuro.
Considerações de custo
Lambda Managed Instances usa precificação baseada em instância em vez de faturamento por invocação. Para cargas de trabalho em estado estável acima de aproximadamente 9 requisições por segundo, o custo fixo de instância é menor do que cobranças equivalentes de GB-segundo do Lambda padrão. Você pode usar a calculadora de preços oficial para comparar custos de Managed Instances e Lambda padrão.
Experimente com sua versão de runtime
Esses benchmarks usam Java 25 com Spring Boot 4.0.6. O repositório GitHub também inclui configurações para Java 21 com Spring Boot 3.x. O README do repositório orienta você através da implantação, teste de carga e coleta de suas próprias métricas.
Conclusão
Esta publicação demonstra como Lambda Managed Instances resolve uma incompatibilidade essencial de Java-em-serverless. O compilador JIT da JVM precisa de tempo para otimizar caminhos de código quentes. Lambda padrão recicla ambientes antes que a JVM atinja otimização máxima. Managed Instances mantém a JVM viva entre invocações, permitindo que o compilador C2 atinja otimização máxima. Os benchmarks mostram o impacto. Nestes benchmarks, Managed Instances entregou latência p50 18 a 30% mais rápida do que Lambda padrão. A latência de cauda melhorou 27 a 41% em p99. Os tempos de resposta máximos caíram 3 a 30x em cargas de trabalho limitadas por CPU. A melhoria de 3,8x apenas da otimização JIT mostra o que é possível quando o runtime tem tempo para completar seu trabalho.
Para mais informações, consulte a documentação do Lambda Managed Instances. O repositório GitHub contém o código de benchmark completo, templates SAM e instruções de implantação. Compartilhe seus resultados nos comentários e deixe a comunidade saber como Managed Instances performa em suas cargas de trabalho. Para excluir todos os recursos de benchmark e evitar cobranças contínuas, execute os comandos de limpeza documentados no README do repositório GitHub.
Este conteúdo foi traduzido do post original do blog, que pode ser encontrado aqui.
Autores
![]() |
Jay Colodner é TAM (US-SMB) na Amazon Web Services. |
![]() |
Debasis Rath é GenAI Specialist SA na Amazon Web Services. |
Tradutores
![]() |
Daniel Abib é Arquiteto de Soluções Sênior e Especialista em Amazon Bedrock na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e especialização em Machine Learning. Ele trabalha apoiando Startups, ajudando-os em sua jornada para a nuvem.
https://www.linkedin.com/in/danielabib/ |
![]() |
Nicolas Tarzia é Senior Technical Account Manager na AWS, com mais de 13 anos de experiência, com ampla experiência em arquitetura cloud, engenharia e design de software. Atualmente está habilitando empresas do ramo de ISV (Independent Software Vendors) simplificando a operação na nuvem e otimizando os custos em cloud. Sua área de interesse são tecnologias serverless.
https://www.linkedin.com/in/nicolastarzia |



