Inicializações a frio aumentam a latência das funções Lambda. Para resolver esse problema, a AWS oferece Provisioned Concurrency, que minimiza a latência de inicialização a frio, mas vem com custos adicionais.
Nesta publicação, exploraremos a simultaneidade provisionada dinâmica. Esta solução otimiza tanto o custo quanto o desempenho, demonstrado por meio de um exemplo detalhado e código Python do AWS CDK.
Introdução do escritor convidado
Noa Gelber é engenheira de software sênior na CyberArk , especializada em aplicativos Serverless SaaS na AWS. Ela tem mais de 20 anos de experiência no desenvolvimento de software de missão crítica.
Você pode seguir Noa em seu Página do LinkedIn .
Índice
Problemas de inicialização a frio do Lambda
Inicialização a frio do AWS Lambda se refere ao atraso experimentado quando uma função do Lambda é invocada pela primeira vez ou após um período de inatividade. Esse atraso ocorre porque a AWS precisa provisionar os recursos e a infraestrutura necessários para executar a função, resultando em latência antes do início do processamento das solicitações. Uma solução potencial para mitigar inicializações a frio no AWS Lambda é a simultaneidade provisionada.
Para saber mais sobre inicializações a frio e otimizações Lambda, confira esta postagem .
Concorrência Provisionada
Provisioned Concurrency é um recurso do Lambda que prepara ambientes de execução simultânea antes das invocações - Documentação da AWS
A simultaneidade provisionada garante que várias funções do Lambda permaneçam "quentes", o que significa que elas são inicializadas e preparadas para responder prontamente, diferentemente do Lambda sob demanda, que inicializa recursos mediante invocação. A pré-inicialização de um ambiente inclui tarefas como download de código, configuração do ambiente e execução do código de inicialização. Uma abordagem comum para utilizar a simultaneidade provisionada é configurar um número fixo desses ambientes. Saiba mais: Documentação da AWS .
Embora a simultaneidade provisionada ofereça uma solução confiável para minimizar a latência nas funções do AWS Lambda, ela pode ter um efeito colateral negativo de aumento de custos, conforme observado por nosso grupo de engenharia de plataforma na CyberArk .
Nos estágios iniciais do desenvolvimento de nossos serviços SaaS sem servidor, encontramos latência significativa em várias funções do Lambda. A implementação da simultaneidade provisionada resolveu prontamente esse problema. No entanto, logo encontramos um aumento notável em nossas cobranças de conta da AWS. Após investigação, descobrimos que durante períodos de baixa carga de trabalho do Lambda, menos de 20% das instâncias de simultaneidade provisionadas foram utilizadas, resultando em pagamento por recursos não utilizados.
Usar um número fixo de instâncias de simultaneidade provisionadas não é o ideal em pelo menos dois cenários:
Variações de tráfego entre contas da AWS: algumas contas da AWS atendem a propósitos como teste e simulação de ambientes de produção, enquanto outras são usadas como ambientes de produção. Essas contas diferem em seus volumes de tráfego, que adicionalmente variam ao longo do dia.
Variações de tráfego regional: Implantar a função Lambda em várias regiões significa lidar com volumes de tráfego variáveis. Algumas regiões podem ter tráfego maior do que outras.
Em cenários como o acima, um número fixo de instâncias é tipicamente abaixo do ideal. Um número alto fixo de instâncias resulta em instâncias ociosas e cobranças desnecessárias durante tráfego baixo, enquanto um número baixo fixo de instâncias leva a um aumento no número de inicializações a frio durante picos de tráfego. Um número de instâncias dinamicamente variável poderia potencialmente ter um desempenho melhor, otimizando custos e latência.
Concorrência dinâmica provisionada para o resgate
A solução que estamos apresentando aqui foi projetada para gerar economias de custo significativas e aprimorar a utilização de recursos. Ela consegue isso por meio do gerenciamento dinâmico de simultaneidade provisionada usando o Application Auto Scaling Target Tracking . Essa abordagem, que ajusta o número de instâncias de simultaneidade provisionadas em resposta a mudanças no tráfego do cliente, garante a utilização eficiente de recursos e economias de custo substanciais durante períodos de baixo tráfego. Mais importante, ela faz tudo isso enquanto mantém o desempenho de latência otimizado para funções Lambda.
A solução consiste nos seguintes componentes principais:
Application Auto Scaling Target Tracking : Este componente oferece escalonamento de instância de simultaneidade provisionada pelo Lambda sem custos adicionais. Ele usa alarmes e políticas de escalonamento do CloudWatch. Saiba mais: Documentação da AWS .
Política de rastreamento de destino: esta é uma política de dimensionamento projetada para ajustar automaticamente o número de recursos dentro de um grupo de recursos escalável para manter um valor de destino especificado para uma métrica específica. De acordo com esta política, o número de instâncias de simultaneidade provisionadas é dimensionado para manter o nível de instância alinhado com o valor de destino. Para definir políticas de dimensionamento para uma função Lambda, o Application Auto Scaling requer registrá-la como um destino escalável . A métrica pode ser predefinida ou personalizada. Saiba mais: Documentação da AWS .
Alarmes do CloudWatch: dois alarmes do CloudWatch são criados durante a implantação do dimensionamento automático do aplicativo, um acionado para aumentar a escala das instâncias e o outro para reduzi-las de acordo com a política de rastreamento de destino.
O dimensionamento automático de aplicativos gerencia dinamicamente instâncias de simultaneidade provisionadas dentro de um intervalo especificado monitorando dois alarmes críticos. Esses alarmes são acionados em resposta a alterações no valor de uma métrica, garantindo que a contagem de instâncias permaneça alinhada com o valor de destino configurado. Utilizaremos uma métrica de utilização de simultaneidade provisionada personalizada para essa finalidade.
O primeiro alarme do CloudWatch dispara quando a métrica de utilização de simultaneidade provisionada ultrapassa o valor alvo por um período sustentado de mais de 3 pontos de dados , com duração mínima de 3 minutos. Em resposta, o dimensionamento automático do aplicativo aumenta a contagem de instâncias de simultaneidade provisionadas.
Por outro lado, o segundo alarme do CloudWatch dispara quando a métrica de utilização de simultaneidade provisionada permanece abaixo de 90% do valor alvo por uma duração estendida de 15 pontos de dados , com duração mínima de 15 minutos. Em resposta, o dimensionamento automático do aplicativo diminui a contagem de instâncias de simultaneidade provisionadas.
Como uma observação lateral, por padrão, os alarmes do Application Auto Scaling estão usando a estatística média da métrica. De acordo com os documentos da AWS , a métrica de utilização de simultaneidade provisionada deve ser visualizada usando a estatística MAX. Além disso, é essencial definir uma métrica personalizada visando a estatística máxima para garantir o gerenciamento eficiente de cargas de tráfego de pico.
O mecanismo em ação
Considere uma função Lambda configurada com simultaneidade provisionada e uma política de rastreamento de destino, onde o número mínimo de instâncias é definido como 1, o número máximo de instâncias é definido como 5 e o valor de destino para a métrica de utilização de simultaneidade provisionada personalizada é definido como 0,7, representando 70% de utilização – de acordo com o seguinte exemplo da AWS .
Aumentando a escala
As figuras a seguir mostram os resultados de nossa experimentação com simultaneidade provisionada dinâmica. Ao examinar a métrica de utilização de simultaneidade provisionada na figura a seguir, observamos que após um pico repentino às 17:52, o valor de utilização de simultaneidade provisionada atingiu 1 , indicando 100% de utilização das instâncias alocadas. Esse valor excede o valor alvo de 0,7, ultrapassando o limite do primeiro alarme do CloudWatch :
Depois que 3 pontos de dados são medidos para essa métrica, o alarme de aumento de escala do CloudWatch é ativado, e a política de dimensionamento de rastreamento de destino inicia um aumento nas instâncias de simultaneidade provisionadas. Essa ação pode ser monitorada na página de configuração do alias, cujas capturas de tela aparecem a seguir. Nesse cenário, antes do burst, havia duas instâncias:
Quando a operação estiver concluída, o número de instâncias será aumentado para três.
Reduzindo a escala
Por volta das 18h07, o tráfego diminui e a utilização de simultaneidade provisionada também diminui para 0,3, indicando uma utilização de 30% das instâncias, o que está abaixo de 90% do valor alvo de 0,7, cruzando assim o limite do segundo alarme do CloudWatch:
Após 15 pontos de dados consistentes abaixo da taxa de utilização (15 minutos no nosso caso), a política de rastreamento de destino aciona a operação de redução, reduzindo o número de instâncias para 1.
Mergulho profundo na solução
Agora que cobrimos os principais elementos e vimos um exemplo simples de como eles funcionam na prática, vamos rever as etapas de implementação com o exemplo de código CDK:
Esse CDK construct aplica simultaneidade provisionada dinâmica sobre uma função Lambda de acordo com estas etapas:
Crie um alias:
Linha 12: Criação de um alias para o Lambda, que é necessário para configurar a simultaneidade provisionada. Neste exemplo, definimos o número inicial de instâncias como 5.
Até esta linha, definimos um Lambda com configuração de simultaneidade provisionada usando um número estático de instâncias.
Crie uma métrica personalizada:
Linhas 16 a 21: Crie uma métrica personalizada com base na métrica de utilização de simultaneidade provisionada .
O parâmetro 'metric_name' representa o nome da métrica personalizada.
O parâmetro 'statistic' especifica a função de agregação aplicada aos dados métricos.
O parâmetro 'unidade' indica a unidade de medida para a estatística da métrica.
O parâmetro 'período' especifica o intervalo de tempo para coleta de dados métricos a serem agregados com base em uma estatística especificada. Nesse caso, o intervalo é configurado como 1 minuto, alinhando-se com o alarme definido pelo Application Auto Scaling Target Tracking , que tem um período de avaliação de 1 minuto.
Agora, vamos configurar a simultaneidade provisionada dinâmica:
Registro de alvo escalável:
Linhas 23-27: Registre o alias da função Lambda como um destino escalável , definindo valores mínimo e máximo para o número de instâncias de simultaneidade provisionadas.
Linha 28: A criação do objeto de destino escalável é definida como dependente do objeto alias do Lambda.
Definir a política de rastreamento de metas:
Linha 29: Configure uma política de rastreamento de alvos com base no métrica de utilização de simultaneidade provisionada que é personalizada com um valor alvo de 0,7. No entanto, é recomendado ajustar esse valor de acordo com os padrões de tráfego do Lambda.
Advertências sobre a solução
Definindo o valor alvo da métrica
Por experiência própria, definir o valor alvo significativamente mais alto do que o mínimo pode resultar em partidas a frio durante explosões repentinas de atividade. O Lambda pode não escalar rápido o suficiente para lidar com o aumento de carga, levando ao subprovisionamento. Considerando que o escalonamento leva no mínimo 3 minutos, é preferível manter um certo nível de instâncias quentes prontas para processar solicitações. Reduzir o limite pode ajudar a evitar o subprovisionamento, permitindo que o Lambda escale mais agressivamente em resposta ao aumento da demanda.
Por outro lado, definir o valor alvo muito baixo dentro do intervalo pode levar ao provisionamento excessivo de instâncias, o que é indesejável devido ao aumento de custos. Além disso, um limite baixo pode disparar eventos de dimensionamento frequentes em resposta a pequenas flutuações na demanda, aumentando potencialmente a latência.
No final das contas , tudo se resume a encontrar o equilíbrio certo entre custo e desempenho e determinar quanto você está disposto a investir para fornecer a melhor experiência ao cliente.
Alarme de redução de escala
Os alarmes do CloudWatch gerados pelo Application Auto Scaling Target Tracking são configurados para interpretar dados ausentes como 'ausentes'. Para saber mais sobre como os alarmes do CloudWatch lidam com dados ausentes, consulte os documentos da AWS .
Em relação ao alarme de redução de escala, se não houver tráfego, não haverá dados para a métrica e, consequentemente, o alarme não será ativado. Esse cenário pode resultar em excesso de provisionamento e custos desnecessários durante períodos sem tráfego. Portanto, é aconselhável definir o valor inicial de simultaneidade provisionada com base no padrão de tráfego da função Lambda. Por exemplo, Lambdas com baixo tráfego podem ser inicializados com um número menor de instâncias.
Resumo
Vimos como podemos reagir proativamente a aumentos no tráfego ajustando a simultaneidade provisionada, esperando demanda sustentada ou consistente. Então, conforme o tráfego diminui, o serviço reduz dinamicamente as instâncias provisionadas, alinhando a alocação de recursos com a carga de trabalho reduzida.
Ao implementar uma solução de simultaneidade provisionada dinâmica, as funções Lambda podem manter a utilização otimizada da simultaneidade provisionada , garantindo assim alocação eficiente de recursos e economia de custos. No entanto, é importante observar que esta não é uma solução mágica. Faça sua pesquisa e encontre o equilíbrio ideal que atenda às suas necessidades específicas .
Agradecimentos especiais
Gostaria de agradecer a Ran Isenberg por dedicar seu tempo para revisar esta postagem e compartilhar seus valiosos insights e feedback,
Daniel Urieli pelas discussões úteis e feedback valioso, e Alon Sadovski por fornecer informações valiosas.
Comentarios