O blog da AWS

Entendendo e remediando as partidas a frio (cold starts): uma perspectiva do AWS Lambda

Por Aakash Bhattacharya, engenheiro de software para AWS Lambda na Amazon Web Services e Tian Wen, gerente de engenheraria de software na Amazon Web Services.

As partidas a frio, inicialização a frio ou cold start são uma consideração importante ao criar aplicativos em plataformas Serverless. No AWS Lambda, eles se referem às etapas de inicialização que ocorrem quando uma função é invocada após um período de inatividade ou durante um rápido aumento de escala. Embora normalmente breves e pouco frequentes, as partidas a frio podem introduzir latência adicional, tornando essencial compreendê-las, especialmente ao otimizar o desempenho em cargas de trabalho responsivas e sensíveis à latência.

Nesta publicação, você entenderá melhor o que são as partidas a frio, como elas podem afetar o desempenho do seu aplicativo e como você pode projetar suas cargas de trabalho para reduzir ou eliminar seu impacto. Com as estratégias e ferramentas certas fornecidas pela AWS, você pode gerenciar com eficiência os cold starts e oferecer uma experiência consistente e de baixa latência para seus usuários.

O que é uma partida a frio?

Os cold starts ocorrem porque plataformas Serverless, como o AWS Lambda, são projetadas para oferecer economia — você não paga por recursos computacionais quando seu código não está em execução. Como resultado, o Lambda só provisiona recursos quando necessário. Uma inicialização a frio acontece quando não há um ambiente de execução existente disponível e um novo deve ser criado. Isso pode acontecer, por exemplo, quando uma função é invocada pela primeira vez após um período de inatividade ou durante uma explosão no tráfego que aciona o aumento de escala.

Quando isso ocorre, o Lambda provisiona e inicializa rapidamente um novo ambiente de execução para executar seu código de função. Essa inicialização adiciona uma pequena quantidade de latência à solicitação, mas ocorre apenas uma vez durante o ciclo de vida desse ambiente de execução.

As partidas a frio consistem em várias etapas que compõem a fase de inicialização, que ocorre antes que a função comece a ser executada. Essas etapas ocorrem quando o serviço Lambda cria um novo ambiente de execução, contribuindo para a latência comumente chamada de duração inicial da função, conforme ilustrado no diagrama a seguir:

Figura 1: Ciclo de vida de execução da função Lambda: componentes de inicialização a frio

  • Provisionamento de containers: o Lambda aloca os recursos computacionais necessários para executar a função, com base na memória configurada.
  • Inicialização do runtime: o Lambda carrega o ambiente de execução da linguagem (Node.js, Python, Java etc.) no container. Você também pode definir um runtime personalizado usando a Lambda Runtime Interface.
  • Carregamento do código da função: o Lambda baixa e descompacta o código da função no container.
  • Resolução de dependência: o Lambda carrega as bibliotecas e pacotes necessários para que a função possa ser executada com êxito.

Embora as partidas a frio normalmente afetem menos de 1% das solicitações, elas podem introduzir variabilidade de desempenho nas cargas de trabalho em que o Lambda precisa criar novos ambientes de execução com mais frequência, como após períodos de inatividade ou durante o rápido escalonamento. Essa variabilidade pode afetar os tempos de resposta percebidos, especialmente em aplicativos sensíveis à latência, como APIs voltadas para o usuário.

Por que ocorrem partidas a frio?

As partidas a frio são um aspecto natural do modelo de computação Serverless devido aos seus princípios básicos de design:

  • Eficiência de recursos: para otimizar o uso de custos e recursos, o AWS Lambda encerra automaticamente ambientes de execução ociosos após um período de inatividade. Quando a função é invocada novamente, um novo ambiente deve ser provisionado.
  • Segurança e isolamento: cada ambiente de execução do Lambda é executado em um container isolado para garantir fortes limites de segurança entre as invocações. Esse isolamento em nível de container requer um novo processo de inicialização, o que aumenta a latência de inicialização.
  • Escalonamento automático: o Lambda cria automaticamente novos ambientes para lidar com o aumento do tráfego ou invocações simultâneas. Cada novo ambiente exige provisionamento e inicialização, o que contribui para a latência de inicialização a frio.

Entendendo e otimizando os fatores de partida a frio

As seções a seguir exploram os fatores que contribuem para as partidas a frio e as técnicas de otimização para inicializar suas funções mais rapidamente.

Seleção de runtime

O Lambda oferece suporte a várias linguagens de programação por meio de runtimes, incluindo a capacidade de criar runtimes personalizados. Um runtime lida com as principais responsabilidades, como retransmitir eventos de invocação, contexto e respostas entre o serviço Lambda e seu código de função. O tempo necessário para inicializar um runtime pode variar dependendo do idioma. Linguagens interpretadas, como Python e Node.js, normalmente inicializam mais rápido, enquanto linguagens compiladas, como Java ou .NET, podem demorar mais devido a etapas adicionais de inicialização, como carregar classes. Os runtimes personalizados ou somente do sistema operacional geralmente oferecem o desempenho mais rápido de inicialização a frio, pois normalmente executam binários compilados no ambiente Linux subjacente.

Os runtimes são regularmente mantidos e atualizados pela AWS, com versões mais recentes geralmente oferecendo melhorias em desempenho, segurança e latência de inicialização. Para aproveitar essas melhorias, a AWS recomenda manter suas funções atualizadas com os últimos runtimes suportados.

Empacotamento e camadas

O AWS Lambda oferece suporte a duas opções de empacotamento para implantar seu código de função: arquivos ZIP e imagens de container. Cada abordagem oferece vantagens exclusivas e pode influenciar a latência de inicialização a frio, dependendo de como é usada.

Para implantações baseadas em ZIP, você pode carregar seu código de função diretamente (até 50 MB) ou por meio do Amazon Simple Storage Service (Amazon S3) (até 250 MB descompactados). Para promover a reutilização, o Lambda também oferece suporte a camadas do Lambda, permitindo que você compartilhe código, bibliotecas ou dependências de runtime comuns em várias funções. No entanto, pacotes maiores podem afetar a latência de inicialização a frio devido a fatores como maior tempo de download do S3, sobrecarga de extração de ZIP, montagem e inicialização de camadas. O tamanho e o número de dependências afetam diretamente o tempo de inicialização — cada dependência adicionada aumenta o tamanho do artefato de implantação, que o Lambda deve baixar, descompactar e inicializar durante a fase de inicialização.

Para otimizar o desempenho da inicialização a frio, mantenha seus pacotes ZIP de implantação pequenos, remova dependências não utilizadas com técnicas como descritas aqui, priorize bibliotecas leves, exclua arquivos desnecessários, como testes ou documentos, e estruture suas camadas com eficiência.

Ao usar implantações baseadas em containers, primeiro você envia sua imagem de função para o Amazon Elastic Container Registry (Amazon ECR). Essa opção oferece maior flexibilidade e controle sobre o ambiente de execução, especialmente útil quando seu código de função excede 250 MB ou quando você precisa de uma versão de linguagem específica ou de bibliotecas do sistema não incluídas nos runtimes gerenciados pela AWS. Embora as imagens de container permitam implantações altamente personalizadas, extrair imagens grandes do ECR pode contribuir para a latência de inicialização a frio. Semelhante à abordagem baseada em ZIP, certifique-se de manter o tamanho mínimo das imagens removendo artefatos desnecessários.

Alocação de recursos

A alocação de memória desempenha um papel fundamental no desempenho e no custo de suas funções do Lambda. Quando você atribui mais memória a uma função, o Lambda também aloca mais potência de CPU, o que pode ajudar a reduzir o tempo necessário para inicializar e executar seu código, geralmente melhorando o desempenho da inicialização a frio.

Use a ferramenta AWS Lambda Power Tuning para equalizar os benefícios de desempenho com o custo adicional de alocação de mais memória. Essa ferramenta executa sua função com diferentes configurações de memória e analisa as compensações entre velocidade e custo. Isso facilita a localização da configuração mais econômica para sua carga de trabalho.

Configuração de rede

Por padrão, suas funções do Lambda estão conectadas à Internet pública, mas você pode anexá-las à sua própria Amazon Virtual Private Cloud (Amazon VPC), por exemplo, quando suas funções precisam acessar recursos hospedados em VPC, como bancos de dados. Quando isso acontece, o serviço Lambda cria uma interface de rede elástica (ENI) à qual anexar suas funções. Esse processo envolve várias etapas, como criação de interfaces de rede, sub-redes, grupos de segurança, tabela de rotas e assim por diante. Embora o serviço Lambda tente minimizar a latência adicional, a aplicação dessa configuração pode introduzir latência adicional, portanto, você só deve usá-lo quando o acesso aos recursos da VPC for necessário.

Considerações de design

A otimização do código de inicialização da função pode ajudar a reduzir as latências de inicialização a frio. Simplifique seu código de função para carregar e se preparar rapidamente, junto com seu ambiente de execução e dependências. Empregue bibliotecas leves e implemente o carregamento lento de recursos para reduzir ainda mais o tempo de inicialização. Minimize o tamanho do código eliminando dependências desnecessárias. Considere sua arquitetura com cuidado: divida funções grandes em unidades menores e mais focadas com base em padrões de invocação. Essa abordagem permite uma inicialização mais rápida de componentes individuais. Essas funções menores e específicas para tarefas oferecem os benefícios adicionais de modularidade aprimorada, testes mais fáceis e manutenção mais simples. No entanto, sempre encontre um equilíbrio entre o tamanho da função e a funcionalidade para manter a eficiência geral do sistema. Ao implementar essas estratégias de otimização, você pode reduzir substancialmente os impactos da inicialização a frio e, ao mesmo tempo, preservar a funcionalidade e o desempenho principais do seu aplicativo.

Concorrência provisionada

A concorrência provisionada aborda partidas frios pré-inicializando ambientes de funções e mantendo-os “aquecidos”, sempre prontos para responder às invocações de funções recebidas. Ao manter ambientes de execução pré-inicializados, o Provisioned Concurrency oferece desempenho consistente para funções frequentemente invocadas, ao mesmo tempo em que elimina a limitação durante picos de carga. A simultaneidade provisionada resulta em desempenho previsível para uma função, fornecendo latência consistente a algum custo para instâncias reservadas. A simultaneidade provisionada é benéfica para aplicativos de alto tráfego que exigem desempenho consistente durante tráfego intenso e aplicativos sensíveis à latência que exigem respostas rápidas para um aplicativo interativo, reduzindo assim as partidas a frio, beneficiando o desempenho geral. A história de sucesso do cliente da Smartsheet demonstra uma melhoria significativa na experiência do usuário com latências reduzidas e melhor eficiência de custos.

Figura 2: Comparação do fluxo de execução do AWS Lambda: simultaneidade padrão versus provisionada

SnapStart

O Lambda SnapStart melhora a latência de partida a frio reduzindo o tempo necessário para que uma função seja inicializada e fique pronta para lidar com solicitações recebidas. Quando o SnapStart está habilitado para uma função, o Lambda cria um snapshot criptografado do ambiente de execução inicializado quando você publica uma nova versão da função. Isso aciona uma fase de inicialização otimizada da função, na qual um snapshot imutável e criptografado da memória e do disco é tirado. Esse snapshot é armazenado em cache para reutilização posterior. Quando uma função habilitada para Snapstart é invocada novamente, o Lambda restaura o ambiente de execução a partir do snapshot em cache em vez de criar um novo ambiente, moderando assim uma invocação fria. O SnapStart minimiza a latência de invocação de uma função, pois a criação de um novo ambiente de execução não exige mais uma fase de inicialização dedicada.

O SnapStart é uma solução eficiente de partidas a frio, atualmente disponível para funções Java, Python e .NET. É particularmente útil para funções com longos tempos de inicialização. Os snapshot inativos são removidos automaticamente após 14 dias sem invocação. Para obter informações detalhadas sobre preços, confira nossa página de preços.

Figura 3: Arquitetura Lambda SnapStart: otimizando inícios a frio por meio da inicialização baseada em snapshot

Observabilidade

Use recursos de observabilidade prontos para uso fornecidos pelo AWS Lambda para investigar se suas funções ou a experiência do usuário são afetadas por partidas a frio e identificar as áreas de otimização mais impactantes. Monitorar o desempenho de inicialização a frio do Lambda usando métricas integradas, como duração do INIT, duração da invocação e taxas de erro, é crucial para identificar gargalos e refinar a função para otimizar o desempenho e a relação custo-benefício. Use as seguintes métricas:

  • Duração do INIT: a métrica de duração do INIT, encontrada na seção logs dos logs da função, mede o tempo necessário para que a função seja inicializada e esteja pronta para lidar com a invocação.
  • Mensagem de relatório: o Lambda relata o tempo total de invocação, como inicialização, na mensagem de log no final de cada invocação. O monitoramento dessa métrica ajuda a identificar possíveis gargalos no código da função.
  • Taxas de erro: o monitoramento das taxas de erro ajuda a identificar problemas na função, garantindo confiabilidade e estabilidade.
  • Métricas de simultaneidade: as métricas de simultaneidade ajudam a entender se uma função está atingindo os limites de simultaneidade que podem contribuir para possíveis aumentos nas durações de inicialização a frio e na aceleração.

Conclusão

Nesta publicação, você aprendeu uma análise detalhada e informações sobre vários aspectos das partidas a frio do Lambda, oferecendo uma compreensão abrangente dos desafios e soluções nesse espaço. Embora as partidas a frio geralmente afetem menos de 1% das solicitações, entender sua natureza e implementar estratégias de remediação apropriadas com antecedência pode ajudar a minimizar seu impacto nos aplicativos mais sensíveis à latência.

Este conteúdo foi traduzido da postagem original do blog, que pode ser encontrada aqui.

Autores

Aakash Bhattacharya é um engenheiro de software para AWS Lambda na Amazon Web Services.
Tian Wen é um gerente de engenheraria de software na Amazon Web Services.

Tradutor

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/

Revisor

Rodrigo Peres é Arquiteto de Soluções na AWS, com mais de 20 anos de experiência trabalhando com arquitetura de soluções, desenvolvimento de sistemas e modernização de sistemas legados.