O blog da AWS

Escalando Aplicações com AWS Lambda

Por Daniel Abib, Enterprise Solution Architect, FSI – LATAM

 

O serviço AWS Lambda foi projetado para implementar tarefas de computação baseadas em eventos, de curta duração, que não retêm ou dependem do estado entre invocações. O serviço do AWS Lambda invoca seu código de negócio sob demanda em resposta a eventos de outros serviços da AWS, solicitações por meio da AWS CLI ou dos SDKs da AWS. O código pode ser executado em até 15 minutos em uma única invocação e uma única função pode usar de 128 MB até 10.240 MB de memória.

A concorrência (concurrency) é o número de solicitações em que sua função do AWS Lambda está executando ao mesmo tempo. Para cada solicitação simultânea, o serviço do AWS Lambda provisiona uma instância separada do seu ambiente de execução. À medida que suas funções recebem mais solicitações, o AWS Lambda lida automaticamente com o dimensionamento do número de ambientes de execução até que você atinja o limite de concorrência da sua conta. Por padrão, o AWS Lambda fornece à sua conta um limite total de concorrência de 1.000 para todas as funções em uma região. Mas, para dar suporte às suas necessidades específicas de conta, você pode solicitar um aumento de cota e configurar controles de concorrência no nível da função para que suas funções críticas não sofram limitação.

Este blog explica a concorrência e o dimensionamento de funções no AWS Lambda. Ao final deste blog, que foi baseado na documentação oficial da AWS, você poderá entender como calcular a concorrência, visualizar as duas principais opções de controle de concorrência (reservadas e provisionadas), estimar as configurações apropriadas de controle de concorrência e exibir métricas para otimização adicional.

Compreendendo e visualizando a concorrência

O AWS Lambda invoca sua função em um ambiente de execução seguro e isolado. Para atender uma solicitação, o AWS Lambda deve primeiro inicializar um ambiente de execução  (a fase inicial Init), antes de usá-lo para Invocar (Invoke) sua função (a fase Invoke).

Na fase de Init (Inic. ou inicialização), o AWS Lambda cria ou descongela um ambiente de execução com os recursos configurados, faz download do código da função e de todas as camadas (layers), inicializa todas as extensões e o runtime, em seguida executa o código de inicialização da função (o código fora do handler principal). O Init é executado durante a primeira invocação, ou antes de invocações de função se você tiver habilitado concorrência provisionada. É o melhor momento para abrir conexões com banco de dados ou recursos externos, porque será executada apenas uma única vez.

O diagrama anterior usa um retângulo para representar um único ambiente de execução. Quando sua função recebe sua primeira solicitação (representada pelo círculo amarelo com rótulo 1), o AWS Lambda cria um novo ambiente de execução e executa o código fora do handler principal durante a fase Inic. (inicialização). Em seguida, o AWS Lambda executa o código do handler principal da função durante a fase Invocar (Invoke). Durante todo esse processo, esse ambiente de execução está ocupado e não pode processar outras solicitações.

Quando o AWS Lambda terminar de processar a primeira solicitação, esse ambiente de execução poderá processar solicitações adicionais para a mesma função. Para solicitações subsequentes, o AWS Lambda não precisa reinicializar o ambiente.

No diagrama anterior, o AWS Lambda reutiliza o ambiente de execução para manipular a segunda solicitação (representada pelo círculo amarelo com rótulo 2), mas reparem que a fase de inicialização (Inic.) não é executada novamente.

Até agora, nos concentramos em apenas uma única instância do seu ambiente de execução (ou seja, uma concorrência de 1). Na prática, o AWS Lambda pode precisar provisionar várias instâncias do ambiente de execução em paralelo para lidar com todas as solicitações de entrada. Quando sua função recebe uma nova solicitação, uma das duas coisas pode acontecer:

  • Se uma instância de ambiente de execução pré-inicializada estiver disponível, o AWS Lambda a usará para processar a solicitação.
  • Caso contrário, o AWS Lambda criará uma nova instância de ambiente de execução para processar a solicitação.

Por exemplo, vamos explorar o que acontece quando sua função recebe 10 solicitações:

No diagrama anterior, cada plano horizontal representa uma única instância de ambiente de execução (rotulada de A a F).

À medida que sua função recebe mais solicitações simultâneas, o AWS Lambda aumenta o número de instâncias do ambiente de execução em resposta.

Para resumir, a concorrência da sua função é o número de solicitações simultâneas que ela está manipulando ao mesmo tempo. Em resposta a um aumento na concorrência da função, o AWS Lambda provisiona mais instâncias do ambiente de execução para atender à demanda de solicitação.

Como calcular a concorrência

Em geral, a concorrência de um sistema é a capacidade de processar mais de uma tarefa simultaneamente. No AWS Lambda, concorrência é o número de solicitações que sua função está manipulando ao mesmo tempo. Uma maneira rápida e prática de medir a concorrência de uma função do AWS Lambda é usar a seguinte fórmula:

Concorrência = (média de solicitações por segundo) * (duração média da solicitação em segundos)

A concorrência difere das solicitações por segundo (TPS).  Por exemplo, suponha que sua função receba 100 solicitações por segundo, em média. Se a duração média da solicitação for de 1 segundo, é verdade que a concorrência também é de 100:

Concorrência = (100 solicitações/segundo) * (1 segundo/solicitação) = 100

No entanto, se a duração média da solicitação for de 500ms, a concorrência será de 50:

Concorrência = (100 solicitações/segundo) * (0. 5 segundos/solicitação) = 50

O que significa uma concorrência de 50 na prática? Se a duração média da solicitação for de 500ms, você poderá pensar em uma instância de sua função como sendo capaz de lidar com 2 solicitações por segundo. Em seguida, são necessárias 50 instâncias da sua função para lidar com uma carga de 100 solicitações por segundo. Uma concorrência de 50 significa que o AWS Lambda deve provisionar 50 instâncias de ambiente de execução para lidar com eficiência com essa carga de trabalho sem qualquer limitação. Veja como expressar isso em forma de equação:

Concorrência = (100 solicitações/segundo) / (2 solicitações/segundo) = 50

Se sua função receber o dobro do número de solicitações (200 solicitações por segundo), mas exigir apenas metade do tempo para processar cada solicitação (250ms), a concorrência ainda será 50:

Concorrência = (200 solicitações/segundo) * (0. 25 segundos/solicitação) = 50

 

Concorrência reservada e concorrência provisionada

Por padrão, sua conta tem um limite de concorrência de 1.000 em todas as funções grande parte das regiões. Suas funções compartilham esse pool de 1.000 concorrências sob demanda. Sua função experimenta limitação (throttling), se você ficar sem concorrência disponível.

Algumas de suas funções podem ser mais críticas do que outras. Como resultado, convém definir configurações de concorrência para garantir que as funções críticas obtenham a concorrência de que precisam. Existem dois tipos de controlos de concorrência disponíveis: concorrência reservada e concorrência provisionada.

  • Use a concorrência reservada para reservar uma parte da concorrência da sua conta para uma função. Isso é útil se você não quiser que outras funções ocupem todas as concorrências não reservadas disponíveis.
  • Use a concorrência provisionada para pré-inicializar várias instâncias de ambiente para uma função. Isso é útil para reduzir as latências de partida a frio.

Concorrência reservada

Se você quiser garantir que uma certa quantidade de concorrência esteja disponível para sua função a qualquer momento, use a concorrência reservada.

A concorrência reservada é o número máximo de instâncias simultâneas que você deseja alocar à sua função. Quando você dedica concorrência reservada a uma função, nenhuma outra função pode usar essa concorrência. Em outras palavras, a configuração de concorrência reservada pode afetar o pool de concorrência que está disponível para outras funções. As funções que não têm concorrência reservada compartilham o pool restante de concorrência não reservada.

A configuração de concorrência reservada conta para o limite geral de concorrência da conta. Não há cobrança para configurar a concorrência reservada para uma função.

Para entender melhor a concorrência reservada, considere o seguinte diagrama:

Neste diagrama, o limite de concorrência da sua conta para todas as funções nessa região está no limite padrão de 1.000. Suponha que você tenha duas funções críticas, função-azul e função-laranja, que rotineiramente esperam obter altos volumes de invocação. Você decide dar 400 unidades de concorrência reservada para a função-azul e 400 unidades de concorrência reservada para função-laranja. Neste exemplo, todas as outras funções em sua conta devem compartilhar as 200 unidades restantes de concorrência não reservada.

O diagrama tem 5 pontos de interesse:

  • Em t1, tanto a função-laranja quanto a função-azul começam a receber solicitações. Cada função começa a usar sua porção alocada de unidades de concorrência reservadas.
  • Em t2, função-laranja e função-azul estão constantemente recebendo mais solicitações. Ao mesmo tempo, você implanta algumas outras funções do AWS Lambda, que começam a receber solicitações. Você não aloca concorrência reservada para essas outras funções. Eles começam a usar as 200 unidades restantes de concorrência sem reservas.
  • Em t3, a função-laranja atinge a concorrência máxima de 400. Embora haja concorrência não utilizada em outro lugar da sua conta, a função-laranja não pode acessá-la. A linha vermelha indica que a função-laranja está enfrentando limitação e o AWS Lambda pode descartar solicitações.
  • Em t4, a função-laranja começa a receber menos solicitações e não está mais sendo limitada. No entanto, suas outras funções experimentam um pico de tráfego e começam a limitar. Embora haja concorrência não utilizada em outro lugar da sua conta, essas outras funções não podem acessá-la. A linha vermelha indica que suas outras funções estão enfrentando limitação.
  • Em t5, outras funções começam a receber menos solicitações e não estão mais sendo limitadas.

A partir deste exemplo, observe que a reserva de concorrência tem os seguintes efeitos:

  • Sua função pode ser dimensionada independentemente de outras funções em sua conta.  Todas as funções da sua conta na mesma região que não têm concorrência reservada compartilham o pool de concorrência não reservada. Sem concorrência reservada, outras funções podem potencialmente usar toda a concorrência disponível. Isso evita que funções críticas sejam ampliadas, se necessário.
  • Sua função não pode ser dimensionada fora de controle.  A concorrência reservada coloca um limite na concorrência máxima da sua função. Isso significa que sua função não pode usar concorrência reservada para outras funções ou concorrência do pool não reservado. Você pode reservar concorrência para impedir que sua função use toda a concorrência disponível em sua conta ou sobrecarregue recursos a jusante.
  • Talvez você não consiga usar todas as concorrências disponíveis da sua conta.  A reserva de concorrência conta para o limite de concorrência da sua conta, mas isso também significa que outras funções não podem usar esse bloco de concorrência reservado. Se a sua função não usar toda a concorrência que você reserva para ela, você está efetivamente desperdiçando essa concorrência. Isso não é um problema, a menos que outras funções em sua conta possam se beneficiar da concorrência desperdiçada.

Para gerenciar as configurações de concorrência reservadas para suas funções, consulte Configurando a concorrência reservada.

Concorrência provisionada

Use a concorrência reservada para definir o número máximo de ambientes de execução reservados para uma função do Lambda. No entanto, nenhum desses ambientes vem pré-inicializado. Como resultado, as invocações de função podem levar mais tempo porque o AWS Lambda deve primeiro inicializar o novo ambiente antes de poder usá-lo para invocar (Invoke) sua função. Quando a inicialização leva mais tempo do que o esperado, isso é conhecido como uma partida a frio (cold start). Para atenuar as partidas a frio, você pode usar a concorrência provisionada.

A concorrência provisionada é o número de ambientes de execução pré-inicializados que você deseja alocar à sua função. Se você definir a concorrência provisionada em uma função, o AWS Lambda inicializará esse número de ambientes de execução para que eles estejam preparados para responder imediatamente às solicitações de função.

Ao usar a concorrência provisionada, o AWS Lambda ainda recicla ambientes de execução em segundo plano. No entanto, a qualquer momento, o AWS Lambda sempre garante que o número de ambientes pré-inicializados seja igual ao valor da configuração de concorrência provisionada da função. Esse comportamento difere da concorrência reservada, em que o AWS Lambda pode encerrar completamente um ambiente após um período de inatividade. O diagrama a seguir ilustra isso comparando o ciclo de vida de um único ambiente de execução quando você configura sua função usando concorrência reservada em comparação com a concorrência provisionada.

Para entender melhor a concorrência provisionada, considere o seguinte diagrama:

Neste diagrama, você tem um limite de concorrência de conta de 1.000. Você decide dar 400 unidades de concorrência provisionada para a função-laranja. Todas as funções em sua conta, incluindo a função-laranja, podem usar as 600 unidades restantes de concorrência sem reservas.

O diagrama tem 5 pontos de interesse:

  • Em t1, função-laranja começa a receber solicitações. Como o AWS Lambda pré-inicializou 400 instâncias do ambiente de execução, o função-laranja está pronta para a invocação imediata.
  • Em t2, a função-laranja atinge 400 solicitações simultâneas. Como resultado, a função-laranja fica sem concorrência provisionada. No entanto, como ainda há concorrência sem reservas disponíveis, o AWS Lambda pode usar isso para lidar com solicitações adicionais para a função laranja (não há limitação). O AWS Lambda deve criar novas instâncias para atender a essas solicitações, e sua função pode enfrentar latências de inicialização a frio.
  • Em t3, a função-laranja retorna a 400 solicitações simultâneas após um breve pico no tráfego. O AWS Lambda é novamente capaz de lidar com todas as solicitações sem latências de início a frio.
  • No t4, as funções da sua conta experimentam uma explosão no tráfego. Essa explosão pode vir da função-laranja ou de qualquer outra função em sua conta. O AWS Lambda usa concorrência sem reservas para lidar com essas solicitações.
  • Em t5, as funções em sua conta atingem o limite máximo de concorrência de 1.000 e experimentam limitação.

O exemplo anterior considerou apenas a concorrência provisionada. Na prática, você pode definir a concorrência provisionada e a concorrência reservada em uma função. Você poderia fazer isso se tivesse uma função que lida com uma carga consistente de invocações, mas rotineiramente vê picos de tráfego durante os fins de semana. Nesse caso, você pode usar a concorrência provisionada para definir uma quantidade de linha de base de ambientes para lidar com a solicitação durante a semana e usar a concorrência reservada para lidar com os picos de fim de semana. Considere o seguinte diagrama:

Neste diagrama, suponha que você configure 200 unidades de concorrência provisionada e 400 unidades de concorrência reservada para a função-laranja. Como você configurou a concorrência reservada, a função-laranja não pode usar nenhuma das 600 unidades de concorrência não reservada.

Este diagrama tem 5 pontos de interesse:

  • Em t1, função-laranja começa a receber solicitações. Como o AWS Lambda pré-inicializou 200 instâncias de ambiente de execução, o função-laranja está pronto para invocação imediata.
  • Em t2, a função-laranja usa toda a sua concorrência provisionada.  função-laranja pode continuar atendendo solicitações usando concorrência reservada, mas essas solicitações podem enfrentar latências de inicialização a frio.
  • Em t3, a função-laranja atinge 400 solicitações simultâneas. Como resultado, a função-laranja usa toda a sua concorrência reservada. Como a função-laranja não pode usar concorrência sem reservas, as solicitações começam a ser limitadas.
  • Em t4, a função-laranja começa a receber menos solicitações e não acelera mais.
  • Em t5, a função-laranja cai para 200 solicitações simultâneas, de modo que todas as solicitações podem novamente usar concorrência provisionada (ou seja, sem latências de inicialização a frio).

Tanto a concorrência reservada quanto a concorrência provisionada contam para o limite de concorrência da sua conta e cotas regionais. Em outras palavras, a alocação de concorrência reservada e provisionada pode afetar o pool de concorrência disponível para outras funções. A configuração da concorrência provisionada incorre em encargos para sua conta da AWS.

Para gerenciar as configurações de concorrência provisionadas para suas funções, consulte Configurando a concorrência provisionada. Para automatizar o dimensionamento de concorrência provisionado com base em uma programação ou utilização de aplicativo, consulte Gerenciando concorrência provisionada com o Application Auto Scaling.

Como recomendação, atente-se ao valor de instâncias reservadas e provisionadas, visando não ter custos desnecessários em sua conta da AWS.

Comparando concorrência reservada e concorrência provisionada

A seguir está uma tabela resumindo e comparando a concorrência reservada e provisionada.

Quotas de concorrência

O AWS Lambda define cotas para a quantidade total de concorrência que você pode usar em todas as funções em uma região. Estas quotas existem a dois níveis:

  • No nível da conta, suas funções podem ter até 1.000 unidades de concorrência por padrão. Para aumentar esse limite, consulte Solicitando um aumento de cota no Guia do Usuário de Cotas de Serviço.
  • No nível da função, você pode reservar até 900 unidades de concorrência em todas as suas funções por padrão. 100 unidades de concorrência são sempre reservadas para funções que não reservam explicitamente a concorrência. Por exemplo, se você aumentou o limite de concorrência da conta para 2.000, poderá reservar até 1.900 unidades de concorrência no nível da função.

Estimar com precisão a concorrência necessária

Se sua função estiver servindo tráfego no momento, você poderá visualizar facilmente suas métricas de concorrência usando as métricas do CloudWatch. Lembre-se de que você também pode calcular a concorrência usando a seguinte fórmula:

Concorrência = (média de solicitações por segundo) * (duração média da solicitação em segundos)

Você pode estimar a média de solicitações por segundo usando a métrica de invocação (invocation) e a duração média da solicitação em segundos usando a métrica de duração (duration).

Métricas de concorrência

Você pode usar as métricas a seguir para monitorar a concorrência de suas funções do Lambda.

Conclusões

 De forma geral, o provisionamento de concorrência e a limitação (throttling) das funções AWS Lambda podem ser melhor gerenciadas com a utilização do parâmetro concorrência reservada. Nos casos em que as aplicações de negócio estão sendo executadas na sua conta AWS e simplesmente precisam de mais do que as 1.000 execuções simultâneas (padrão), a Amazon pode aumentar este limite através de um pedido de aumento de limites.

Embora os limites de concorrência sejam uma ótima indicação da taxa de transações por segundo (TPS) que seu serviço de negócio pode executar, este único fator não contam toda a história, já que a duração média do tempo de execução tem um efeito enorme no número de solicitações que um serviço pode processar em um determinado período de tempo. Ou seja, uma função AWS Lambda que pode ser executada em um processo duas vezes mais rápido precisará de menos execuções simultâneas para lidar com o mesmo número de solicitações, em comparação com uma função mais lenta. Otimize seu código para ser eficiente / performático e aumente o número de transações por segundo que sua solução poderá responder.

 


Sobre o autor

Daniel Abib é Enterprise Solution Architect 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 segurança. Ele trabalha apoiando clientes corporativos, ajudando-os em sua jornada para a nuvem.

https://www.linkedin.com/in/danielabib/