O blog da AWS

Melhorias de escalabilidade ao processar o Apache Kafka com o AWS Lambda

Por Julian Wood
 

O AWS Lambda está aprimorando o comportamento de escalabilidade automática ao processar dados de fontes de eventos do Apache Kafka. O Lambda está aumentando o número padrão de consumidores iniciais, melhorando a rapidez com que os consumidores aumentam a escala e ajudando a garantir que os consumidores não reduzam a escala muito rapidamente. Não há nenhuma ação adicional que você deva realizar e não há custo adicional.

Executando o Kafka na AWS

O Apache Kafka é uma plataforma de código aberto popular para criar pipelines e aplicativos de dados de streaming em tempo real. Você pode implantar e gerenciar sua própria solução Kafka no local ou na nuvem no Amazon EC2.

O Amazon Managed Streaming for Apache Kafka (MSK) é um serviço totalmente gerenciado que facilita a criação e a execução de aplicativos que usam o Kafka para processar dados de streaming. O MSK Serverless é um tipo de cluster para o Amazon MSK que permite que você execute o Kafka sem precisar gerenciar e escalar a capacidade do cluster. Ele provisiona e dimensiona automaticamente a capacidade enquanto gerencia as partições em seu tópico, para que você possa transmitir dados sem pensar em dimensionar ou escalar clusters corretamente. O MSK Serverless oferece um modelo de preços baseado em taxa de transferência, para que você pague somente pelo que usa. Para obter mais informações, consulte Usando o Kafka para criar seu aplicativo de streaming.

Usando o Lambda para consumir registros do Kafka

O processamento de dados de streaming pode ser complexo em arquiteturas tradicionais baseadas em servidores, especialmente se você precisar reagir em tempo real. Muitas organizações gastam tempo e custos significativos gerenciando e escalando suas plataformas de streaming. Para reagir rapidamente, eles devem provisionar a capacidade máxima, o que aumenta a complexidade.

As arquiteturas Lambda e Serverless eliminam o trabalho pesado indiferenciado ao processar fluxos do Kafka. Você não precisa gerenciar a infraestrutura, pode reduzir a sobrecarga operacional, reduzir os custos e escalar sob demanda. Isso ajuda você a se concentrar mais na criação de aplicativos de streaming. Você pode escrever funções do Lambda em várias linguagens de programação, que oferecem flexibilidade ao processar dados de streaming.

Mapeamento da fonte de eventos do Lambda

O Lambda pode se integrar nativamente aos seus ambientes Kafka como consumidor para processar dados de stream assim que forem gerados.

Para consumir dados de streaming do Kafka, você configura um mapeamento de origem de eventos (ESM – Event Source Mapping) em suas funções do Lambda. Esse é um recurso gerenciado pelo serviço Lambda, que é separado da sua função. Ele pesquisa continuamente os registros dos tópicos do cluster Kafka. Opcionalmente, o ESM filtra os registros e os agrupa em uma carga útil. Em seguida, ele chama a API Lambda Invoke para entregar a carga à sua função do Lambda de forma síncrona para processamento.

Como o Lambda gerencia as pesquisas, você não precisa gerenciar uma frota de consumidores em várias equipes. Cada equipe pode criar e configurar seu próprio ESM com o Lambda gerenciando a pesquisa.

AWS Lambda event source mappingMapeamento da fonte de eventos do AWS Lambda

Para obter mais informações sobre como usar o Lambda para processar streams do Kafka, consulte o guia de aprendizado.

Escalabilidade e produtividade

O Kafka usa partições para aumentar a taxa de transferência e distribuir a carga de registros para todos os corretores em um cluster.

O recurso de mapeamento da fonte de eventos do Lambda inclui pollers e processadores. Os pollers têm consumidores que leem registros das partições de Kafka. Os responsáveis pelo poller enviam aos processadores que agrupam os registros e invocam sua função.

Quando você cria um mapeamento de origem de eventos do Kafka, o Lambda aloca consumidores para processar todas as partições no tópico do Kafka. Anteriormente, a Lambda alocava no mínimo um processador para um consumidor.

Lambda previous initial scaling

Escalabilidade inicial anterior do Lambda

Com essas melhorias de escalabilidade, o Lambda aloca vários processadores para melhorar o processamento. Isso reduz a possibilidade de uma única invocação desacelerar todo o fluxo de processamento.

Lambda updated initial scaling

Escalabilidade inicial atualizada do Lambda

Cada consumidor envia registros para vários processadores em execução em paralelo para lidar com o aumento das cargas de trabalho. Os registros em cada partição são atribuídos somente a um único processador para manter a ordem.

O Lambda aumenta ou diminui automaticamente o número de consumidores e processadores com base na carga de trabalho. O Lambda faz uma amostra do atraso de compensação do consumidor de todas as partições no tópico a cada minuto. Se o atraso estiver aumentando, isso significa que o Lambda não consegue acompanhar o processamento dos registros da partição.

O algoritmo de escalabilidade considera o atraso de compensação atual e também a taxa de novas mensagens adicionadas ao tópico. O Lambda pode atingir o número máximo de consumidores em três minutos para reduzir o atraso de compensação o mais rápido possível. O Lambda também está reduzindo o comportamento de redução de escala para garantir que os registros sejam processados mais rapidamente e a latência seja reduzida, especialmente para cargas de trabalho intermitentes.

O total de processadores para todos os pollers só pode ser ampliado até o número total de partições no tópico.

Após invocações bem-sucedidas, o pesquisador submete periodicamente as compensações aos respectivos corretores.

Lambda further scalingEscalabilidade adicional do Lambda

Você pode monitorar a produtividade do seu tópico do Kafka usando as métricas de consumo consumer_lag e consumer_offset.

Para verificar quantas invocações de função ocorrem em paralelo, você também pode monitorar as métricas de simultaneidade da sua função. A simultaneidade é aproximadamente igual ao número total de processadores em todos os pollers, dependendo da atividade do processador. Por exemplo, se três pollers tiverem cinco processadores em execução para um determinado ESM, a simultaneidade da função seria de aproximadamente 15 (5 + 5 + 5).

Vendo a escalabilidade aprimorada em ação

Há vários padrões Serverless que você pode usar para processar fluxos do Kafka usando o Lambda. Para configurar o Amazon MSK Serverless, siga as instruções no repositório do GitHub:

  1. Crie um exemplo de tópico Amazon MSK Serverless com 1000 partições.
./kafka-topics.sh --create --bootstrap-server "{bootstrap-server}" --command-config client.properties --replication-factor 3 --partitions 1000 --topic msk-1000p
Bash

2. Adicione registros ao tópico usando um UUID como chave para distribuir os registros uniformemente entre as partições. Este exemplo adiciona 13 milhões de registros.

for x in {1..13000000}; do echo $(uuidgen -r),message_$x; done | ./kafka-console-producer.sh --broker-list "{bootstrap-server}" --topic msk-1000p --producer.config client.properties --property parse.key=true --property key.separator=, --producer-property acks=all
Bash

3. Crie uma função Python com base nesse padrão, que registra os registros processados.

4. Altere o código da função para inserir um atraso de 0,1 segundos para simular o processamento do registro.

import json
import base64
import time

def lambda_handler(event, context):
    # Define a variable to keep track of the number of the message in the batch of messages
    i=1
    # Looping through the map for each key (combination of topic and partition)
    for record in event['records']:
        for messages in event['records'][record]:
            print("********************")
            print("Record number: " + str(i))
            print("Topic: " + str(messages['topic']))
            print("Partition: " + str(messages['partition']))
            print("Offset: " + str(messages['offset']))
            print("Timestamp: " + str(messages['timestamp']))
            print("TimestampType: " + str(messages['timestampType']))
            if None is not messages.get('key'):
                b64decodedKey=base64.b64decode(messages['key'])
                decodedKey=b64decodedKey.decode('ascii')
            else:
                decodedKey="null"
            if None is not messages.get('value'):
                b64decodedValue=base64.b64decode(messages['value'])
                decodedValue=b64decodedValue.decode('ascii')
            else:
                decodedValue="null"
            print("Key = " + str(decodedKey))
            print("Value = " + str(decodedValue))
            i=i+1
            time.sleep(0.1)
    return {
        'statusCode': 200,
    }
Python

5. Configure o ESM para apontar para o cluster e o tópico criados anteriormente.
6. Use o tamanho de lote padrão de 100. Defina a StartingPosition como TRIM_HORIZON para processar desde o início do fluxo.
7. Implante a função, que também adiciona e configura o ESM.
8. Veja as métricas ConcurrentExecutions e OffsetLag do Amazon CloudWatch para ver o processamento.

Com as melhorias de escalabilidade, depois que o ESM é configurado, o ESM e a função aumentam para lidar com o número de partições.

Lambda automatic scaling improvement graphGráfico de melhoria do escalonamento automático do Lambda

Aumento da produtividade do processamento de dados

É importante que sua função consiga acompanhar a taxa de tráfego. Um atraso crescente de compensação significa que o processamento da função não consegue acompanhar o ritmo. Se a idade for alta em relação ao período de retenção da transmissão, você poderá perder dados à medida que os registros expirarem da transmissão.

Esse valor geralmente não deve exceder 50% do período de retenção do stream. Quando o valor atinge 100% do período de retenção do stream, os dados são perdidos. Uma solução temporária é aumentar o tempo de retenção do fluxo. Isso lhe dá mais tempo para resolver o problema antes de perder dados.

Há várias maneiras de melhorar a produtividade do processamento.

  1. Evite processar registros desnecessários usando a filtragem de conteúdo para controlar quais registros o Lambda envia para sua função. Isso ajuda a reduzir o tráfego para sua função, simplifica o código e reduz o custo geral.
  2. O Lambda aloca processadores em todos os pollers com base no número de partições até o máximo de uma função Lambda simultânea por partição. Você pode aumentar o número de funções de processamento do Lambda aumentando o número de partições.
  3. Para funções de computação intensiva, você pode aumentar a memória alocada para sua função, o que também aumenta a quantidade de CPU virtual disponível. Isso pode ajudar a reduzir a duração de uma função de processamento.
  4. O Lambda pesquisa Kafka com um tamanho de lote configurável de registros. Você pode aumentar o tamanho do lote para processar mais registros em uma única invocação. Isso pode melhorar o tempo de processamento e reduzir os custos, principalmente se sua função tiver um tempo de inicialização maior. Um tamanho de lote maior aumenta a latência para processar o primeiro registro no lote, mas potencialmente diminui a latência para processar o último registro no lote. Há uma compensação entre custo e latência ao otimizar a capacidade de uma partição, e a decisão depende das necessidades de sua carga de trabalho.
  5. Garanta que seus produtores distribuam uniformemente os registros entre as partições usando uma estratégia eficaz de chave de partição. Uma carga de trabalho fica desequilibrada quando uma única chave domina outras chaves, criando uma partição ativa, o que afeta a taxa de transferência.

Consulte Aumentar a produtividade do processamento de dados para obter algumas orientações adicionais.

Conclusão

Hoje, o AWS Lambda está aprimorando o comportamento de escalabilidade automática ao processar dados de fontes de eventos do Apache Kafka. O Lambda está aumentando o número padrão de consumidores iniciais, melhorando a rapidez com que eles aumentam a escala e garantindo que eles não diminuam a escala muito rapidamente. Não há nenhuma ação adicional que você deva realizar e não há custo adicional.

Você pode explorar as melhorias de escalabilidade com suas cargas de trabalho existentes ou implantar um cluster Amazon MSK e experimentar um dos padrões para medir o tempo de processamento.

Para explorar o uso do Lambda para processar streams do Kafka, consulte o guia de aprendizado.

Para obter mais recursos de aprendizado Serverless, visite Serverless Land.

 

Este artigo foi traduzido do Blog da AWS em Inglês.

 


Sobre o autor

Julian Wood é Developer Advocate Sênior na Amazon Web Services (AWS) e ajuda desenvolvedores e criadores a adotar Serverless como a tecnologias que podem transformar a maneira como criam e executam aplicativos.

 

 

 

 

Tradutor

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/