Estratégias para manter a alta disponibilidade utilizando AWS Lambda

Danilo Paggi
ReZÉnha
Published in
8 min readMar 11, 2022

“Vixi, o sistema caiu!” (Pessoa em desespero)

Uma frase temida que sempre vem acompanhada de várias ligações, e-mails e uma corrida contra o tempo para que seja estabilizado o mais rápido possível.

E se pudéssemos blindar nosso sistema contra esses acontecimentos, ou, ao menos, garantir que ele seja resistente o suficiente para que estes momentos sejam cada dia mais raros?

Vem com a gente, que vamos descobrir como fazemos essa prevenção aqui no Zé em um sistema baseado no serviço AWS Lambda.

O serviço AWS Lambda

O serviço da AWS Lambda pertence à gama de serviços oferecidos pela cloud Amazon Web Service (AWS) e atende a arquitetura serverless, onde se executa aplicações sem a necessidade de gerenciar os servidores. Já tivemos um artigo todo dedicado a ela que aborda detalhadamente pontos importantes para o melhor entendimento do serviço que citaremos mais superficialmente abaixo.

Ciclo de vida

Ao receber uma solicitação de processamento para a Lambda, a AWS sobe uma micro VM (Firecracker Micro Virtual Machine) com as configurações estabelecidas, este servidor processa a solicitação, responde a requisição e, se não houver outra requisição que utilize a mesma Lambda, a desativa após a resposta.

Cobrança

A cobrança é realizada pelo número de execuções da Lambda, o tempo que elas gastam no processamento e a quantidade de memória que desejamos que seja dedicada a elas dentro da VM gerenciada pela AWS.

Cold Start

É o nome dado ao tempo que a AWS gasta para subir essa micro VM configurada e inicializada para responder a solicitação. Ele ocorre quando não há nenhuma outra VM disponível para o mesmo evento, em espera, e que ainda não tenha começado o fluxo de encerramento.

Nossa arquitetura com Lambdas

Os nossos clientes externos e internos acessam os serviços em Lambda passando pelo serviço Amazon API Gateway, que direciona para a Lambda responsável pelo processamento daquele tipo de solicitação, que, por sua vez, pode se utilizar de uma base de dados alocado no serviço Amazon Aurora ou Amazon Dynamo.

Para entender como fazemos para que os bancos de dados consigam acompanhar o fluxo das Lambdas é possível se aprofundar neste artigo.

Escalonando com Lambda

A função Lambda dispõe de duas configurações que, em conjunto, ajudam muito o tratamento do aumento das requisições de execução: Reserved e o Auto Scaling.

Reserved

Nesta abordagem, nós definimos um número de Lambdas, dentro do limite da conta, que só poderão ser utilizadas pela Lambda respectiva da reserva. Desta forma, garantimos que sempre haverá um número disponível de recursos para atender as chamadas para aquela Lambda específica.

Auto scaling

Nesta abordagem, a própria AWS se compromete a escalar as Lambdas para atender as requisições (Linha roxa) de forma automática e acompanhando o seu fluxo de aumento ou declínio (Linha Laranja), respeitando o limite de execuções simultâneas da conta.

Um monstro chamado throttle

Além de eventuais problemas de codificação e banco de dados, o throttle é um ofensor poderoso contra a disponibilidade de um sistema e é originado devido a um modelo de gestão de recursos utilizado pela AWS chamado algoritmo do balde furado (Leaky bucket algorithm).

Neste modelo, o uso de um recurso vai sendo escalado conforme o número de requisições até um limite, onde, a partir deste, as demais solicitações receberão um retorno de erro (throttle) até que sejam liberados recursos para o atendimento. Entretanto, não é apenas o fim dos recursos disponíveis que ocasiona o throttle, a demora para disponibilizar este recurso (mesmo que com capacidade disponível) pode ser um causador também.

Burst Concurrency

https://docs.aws.amazon.com/pt_br/lambda/latest/dg/invocation-scaling.html

O processo dentro da AWS que efetua o auto scaling da Lambda acompanhando o aumento da demanda do mesmo é chamado de Burst concurrency. Entender o comportamento deste processo é uma chave importante para se prevenir da razão do throttle por velocidade de disponibilização do recurso.

O processo de Burst trata da velocidade que a AWS irá escalonar os recursos para atender uma crescente demanda de uso para a sua conta.

Conforme podemos acompanhar no gráfico, durante os momentos iniciais os recursos são acrescidos em progressão geométrica, apesar de ser uma escalonada agressiva, devemos nos lembrar que o Cold Start faz com que a Lambda não tenha liberação automática após invocação. Neste cenário, níveis de acesso que cresçam mais rápido que uma progressão geométrica gerarão throttle, pois as lambdas, apesar de iniciadas, não estão atendendo ainda.

Como agravante, atingindo determinado limite (Burst limit) a liberação de novos recursos passa a seguir um acréscimo em progressão aritmética até o limite de recursos da conta, assim fazendo que eventuais fluxos de solicitações constante em progressão geométrica, passem a enfrentar não somente o efeito do Cold Start na geração de throttles, como também um impacto adicional ainda maior da diminuição de velocidade na invocação dos recursos, que acabará por criar uma avalanche de throttles em sua aplicação.

Provisionamento de Lambda

O provisionamento da lambda é a alternativa a ser explorada para driblarmos o comportamento da Lambda junto ao Burst Concurrency. Ativando o provisionamento, a AWS já prepara previamente micro VMs para as respectivas funções Lambda às deixando prontas para resposta imediata a eventuais requisições. Desta forma, conseguimos garantir que…

  • … não haverá cold start na utilização;
  • … podemos contornar o burst limit;
  • … e garantir a disponibilidade de Lambdas sempre disponíveis para as requisições.

É muito importante, no caso da utilização do Amazon API Gateway como gatilho para a solicitação, que o mesmo esteja apontando para a versão da Lambda que foi provisionada, garantindo que haverá a utilização do provisionamento para as requisições.

O ponto fraco dessa abordagem é que, dado que a cobrança da Lambda é efetuada também pelo tempo de execução, ou seja, a disponibilidade da mesma, o valor por deixar Lambdas disponíveis por longos tempo é bem alto.

Serviço de provisionamento

Para contar com a disponibilidade que podíamos alcançar na utilização da Lambda, ao mesmo tempo que, minimizar ao máximo os custos que deveriam ser empregados no processo, foi feito, inicialmente, um estudo de nosso histórico de picos de acesso.

Trecho de nosso histórico de picos de acesso

Com o estudo conseguíamos identificar:

  • Os dias e horários de maior pico;
  • A velocidade da escalada de requisições;
  • Os momentos de maior ocorrência de throttles;
  • A quantidade de Lambdas que precisaríamos pra cada pico.

Contando com estes dados, podíamos traçar quando teríamos que provisionar as Lambdas, quantas deveríamos provisionar e até quando precisávamos delas provisionadas, assim nos permitindo otimizar a utilização/custo da nossa necessidade.

Para atender a esse processo de forma automatizada, optamos por criar um serviço para efetuar este provisionamento nas janelas que havíamos mapeado.

O comportamento do serviço

Tanto para o provisionamento das Lambdas, como para a retirada do provisionamento o fluxo segue a seguinte ordem:

  1. Um trigger de event bridge (Cron) programado para atender as datas, horários e dias (definidos no estudo inicial) inicia o processamento da Lambda.
  2. Essa Lambda busca em um banco Dynamo que contém a referência das Lambdas, tratadas como caminhos críticos, e suas configurações de provisionamento respectiva.
  3. A Lambda aplica em todas a listagem obtida no banco o provisionamento necessário, com tempo suficiente para que estejam prontas até o momento do pico de acessos, ou a retirada do provisionamento anteriormente aplicado.

Benefícios obtidos

Nossos ganhos quanto à disponibilidade foram rapidamente notáveis, conforme podemos analisar nos gráficos abaixo retirados do nosso painel de acompanhamento.

O tempo de espera de resposta da Lambda pelo serviço Amazon API Gateway despencou…

E os throttles que nos impactam tanto no percentual de disponibilidade quase que desapareceram

Aprimoramentos futuros

Com o serviço em constante aprimoramento, temos algumas iniciativas de aprimoramento como as citadas abaixo:

Quantidade de provisionamento flexível

Atualmente a quantidade a ser provisionada pelo serviço foi calculada com base no histórico de picos de acesso da aplicação como um todo, sendo assim, todas as lambdas cadastradas no banco Dynamo são provisionadas com a mesma quantidade. Entretanto, sabemos que cada lambda pode apresentar uma necessidade particular, dessa forma, conseguimos otimizar os custos adicionando a possibilidade de personalizar esta quantidade por lambda.

Inteligência de previsão de picos

O serviço de provisionamento foi preparado para se antecipar aos nossos picos de acesso com base no passado, entretanto, não podemos garantir que estes não se alterem em dias ou intensidade no futuro. Para não ser necessário que seja realizado uma análise manual de tempos em tempos, utilizar da engenharia de dados na criação de um modelo de previsibilidade na mudança de comportamento dos picos nos permitiria automatizar essa configuração no serviço de provisionamento.

Automação com ações de marketing

As alterações naturais do comportamento de acessos tendem a ser gradativas, já ações de marketing podem gerar um fluxo intenso de forma muito rápida e fora dos dias de pico esperados. Uma integração com os serviços de agendamento de ações por marketing, geraria uma alinhamento sem ruído ou perda de datas e horários, evitando qualquer surpresa desagradável no impacto da disponibilidade justo em momentos tão importantes de visibilidade da aplicação.

Desde a implantação deste serviço de provisionamento no início de 2021, ele tem feito a diferença nos auxiliando a passar por picos de acesso violentos e nos permitindo garantir que qualquer pessoa tenha sua bebida onde, como e quando quiser (sem sofrer com throttles) 🍻

Artigos relacionados

Recursos

--

--

ReZÉnha
ReZÉnha

Published in ReZÉnha

Todas as pessoas merecem comemorar onde, como e quando quiserem!

Danilo Paggi
Danilo Paggi

Written by Danilo Paggi

Software Engineer @Zé delivery, married — Anime fan and admirer of good conversation 👨🏻‍💻