Como funciona a mensageria com Apache Kafka na prática?

Arquitetura orientada a eventos traz benefícios no processamento paralelizado e evita sobrecarga de requisições e indisponibilidade da aplicação.

Você já se perguntou como grandes e-commerces, por exemplo, processam milhares de pedidos simultaneamente sem que os usuários percebam qualquer lentidão? A resposta está em uma arquitetura orientada a eventos, utilizando mensageria com Apache Kafka.

Neste post, vamos explorar como criar uma aplicação eficiente com Apache Kafka, Spring Boot e Kotlin, destacando os benefícios do uso de coroutines.

O que é mensageria?

Mensageria é uma arquitetura orientada a eventos que processa informações de forma assíncrona, ou seja, em segundo plano. Em outras palavras, isso permite que o usuário não precise esperar pelo processamento completo de uma operação para continuar utilizando o sistema.

Por exemplo, imagine uma loja online que processa centenas de pedidos por minuto. Cada pedido passa por várias etapas: detecção de fraude, emissão de notas, processamento de pagamento, agendamento de frete, entre outras. Ou seja, sem mensageria, o usuário teria que esperar todas essas etapas serem concluídas, o que seria extremamente ineficiente.

Ao realizar um pedido, uma mensagem é enviada para um sistema, que a distribui para diferentes serviços que processam essas etapas simultaneamente. Como resultado, temos mensagens rápidas para os usuários e um processamento eficiente em segundo plano.

Dessa forma, a mensageria garante a diminuição da perda de compras por inatividade ou demora para responder os usuários, enquanto mantém o usuário informado sobre o status da compra por meio do processamento paralelo.

O que é o Apache Kafka?

O Apache Kafka é uma plataforma de streaming de eventos distribuída que funciona como um sistema de mensageria. Ele armazena mensagens em tópicos e permite que múltiplos consumidores processem essas mensagens de forma independente e simultânea.

Arquitetura do Kafka

A arquitetura do Kafka é composta por vários componentes essenciais:

Produtores: Aplicações que enviam mensagens para o Kafka. Eles publicam dados nos tópicos do Kafka, que são então distribuídos entre os consumidores. Por exemplo, uma aplicação de e-commerce pode ser um produtor que envia informações de pedidos ao Kafka.

Consumidores: Aplicações que leem e processam as mensagens do Kafka. Eles se inscrevem nos tópicos e consomem as mensagens, podendo processar dados em tempo real. Por exemplo, um serviço de processamento de pagamentos pode consumir mensagens relacionadas a transações financeiras.

Tópicos: Canais onde as mensagens são publicadas. Cada tópico pode ter várias partições para escalabilidade. Um tópico pode representar, por exemplo, uma categoria específica de dados, como “transações financeiras” ou “logs de servidor”.

Brokers: Servidores que armazenam as mensagens e servem como intermediários entre produtores e consumidores. Um cluster Kafka é composto por vários brokers para garantir a distribuição e a durabilidade dos dados.

ZooKeeper: Usado para coordenação e gerenciamento dos brokers. Ele mantém a configuração do cluster e ajuda na sincronização entre os brokers. No entanto, o Kafka está migrando para um modelo sem ZooKeeper.

Benefícios da mensageria com Kafka

Escalabilidade: O Kafka pode ser escalado horizontalmente adicionando mais brokers e partições.

Desempenho: Alta taxa de transferência e baixa latência, ideal para processamento de dados em tempo real.

Durabilidade: Mensagens são persistidas em disco, garantindo alta durabilidade e confiabilidade.

Flexibilidade: Suporte a múltiplos consumidores e processamento paralelo de mensagens.

Usos práticos da mensageria com Kafka

Monitoramento em tempo real: Análise de logs, métricas de performance e detecção de anomalias.

Processamento de transações financeiras: Transações bancárias, pagamentos e detecção de fraudes.

E-commerce: Processamento de pedidos, inventário em tempo real e recomendações personalizadas.

IoT: Coleta e processamento de dados de sensores em tempo real.

Ferramentas complementares

Para maximizar o uso do Kafka, várias ferramentas podem ser integradas:

Spring Boot: Um framework Java que simplifica a criação de microserviços. Usar Spring Boot com Kafka facilita a configuração e o gerenciamento de aplicações de mensageria. Ele fornece abstrações e templates que agilizam o desenvolvimento.

Kotlin Coroutines: Utilizado para simplificar o código assíncrono. Coroutines permitem escrever código assíncrono de maneira sequencial, facilitando a leitura e manutenção. Quando combinado com Kafka, coroutines podem melhorar a eficiência e o desempenho do processamento de mensagens.

K6: Uma ferramenta para testes de carga que permite simular várias requisições e medir o desempenho da aplicação. Integrar K6 com Kafka ajuda a garantir que o sistema possa lidar com picos de tráfego e cargas pesadas sem degradação de desempenho.

 

Leia também:

O que é Squad as a Service? Saiba quando é hora de contratar

5 ferramentas de IA generativa para desenvolvimento de soluções tecnológicas

Como funciona o Apache Kafka na prática?

Vamos ver como tudo isso funciona? Enfim, vamos ver tudo isso na prática. Os testes a seguir se baseiam em uma API de transferências de pix com duas aplicações: produtor e consumidor.

O produtor é aquele que recebe requisições de transferências de pix e comunica rapidamente para o usuário que o pix está em processamento — status PENDING. O consumidor, por sua vez, é o responsável por realizar o processamento da transação pix em background.

Para facilitar a compreensão, iremos omitir abaixo parte do código, mas você pode encontrá-lo completo no GitHub.

Produtor

Neste exemplo, o produtor é bem simples: um endpoint que recebe as requisições de transferências de pix, salva em um banco de dados e, em seguida, envia a mensagem para o tópico PIX_NEW_ORDER do Kafka.

Os tópicos do Kafka são como filas que irão armazenar a mensagem para os consumidores processarem. Para realizar uma transferência por esse endpoint é preciso informar: id, a chave de origem, a chave de destino e o valor da transferência, conforme exemplo:

O código referente a este endpoint também é bem simples. Ele recebe os valores de entrada armazenados na classe PixDto e depois chama o caso de uso, repassando-os.

O caso de uso tem 3 serviços principais, são eles:

  • CreatePixRepository: Classe encarregada de salvar o pix no banco de dados.
  • PixSendMessage: Classe encarregada de enviar a mensagem para o Kafka, no nosso caso a mensagem são os dados da transferência, id, chave de origem etc.
  • CreatePixMapper: Classe encarregada de transformar os dados de entrada em dados que podem ser salvos ou enviados como mensagem para o Kafka.

Consumidor

Nosso consumidor também não é diferente do que vimos de código até aqui. Neste caso, a diferença é que não é mais um endpoint o ponto inicial da nossa funcionalidade, e sim um consumidor que ficará ouvindo as mensagens salvas no tópico PIX_NEW_ORDER e chamará um caso de uso que contém a lógica para processar as mensagens do Kafka.

O caso de uso valida se as chaves de pix estão corretas e, caso estiverem, ele processa as mensagens e atualiza o status da ordem de transferência para finalizado. Porém, se a validação falhar o status da ordem é atualizado para ERRO e é enviado uma mensagem para a fila de erros.

Obs: A lógica de enviar as mensagens para uma fila ou outra encontra-se na api de producer pois é ela que valida o status da ordem e decide para qual tópico enviar.

Executando a aplicação sem Coroutine

1º passo

Primeiro, iremos executar a aplicação sem usar coroutine. Para isso, basta irmos até a branch: feat/kafka-without-coroutine e executar o docker compose com o comando abaixo:

sudo docker compose up

Dependendo da versão do docker compose, o comando vai ser:

sudo docker-compose up

Esse comando monta todo o cenário subindo as apis de consumidor e produtor, além de também subir o Apache Kafka.

2º Passo

Entrar no /bin/bash do Apache Kafka para acompanhar as mensagens. Para isso, basta executar o comando abaixo em um novo terminal:

sudo docker exec -it pix-kafka /bin/bash

E depois, dentro do bash, executar o comando:

kafka-consumer-groups –bootstrap-server localhost:9092 –describe –all-groups

Esse comando nos mostra todos os consumidores de um tópico do Kafka — no nosso caso, o tópico PIX_NEW_ORDER, que é onde chegarão as mensagens de pix para o processamento.

Algumas propriedades importantes para acompanharmos:

  • CURRENT-OFFSET: Quantidade de mensagens que tem para processar
  • LOG-END-OFFSET: Quantidade de mensagens processadas
  • LAG: Quantidade de mensagens que faltam processar

3º Passo

Entrar na pasta teste de carga e, em um novo terminal, executar o comando abaixo:

sudo docker compose up

Este comando fará com que o teste de carga seja iniciado. O teste de carga chamará o endpoint de transferências de PIX várias vezes e, ao final, exibirá algumas métricas, conforme exemplo:

Repare que o endpoint foi chamado 14077 vezes. Se voltarmos para o 2º terminal e executarmos novamente o comando do passo 2, podemos ver o atraso das mensagens. Depois de um certo tempo todas foram consumidas com sucesso.

Repare que as 14077 mensagens foram processadas com êxito, levando mais ou menos 5 minutos para processar todas. A ideia aqui é executar o comando do teste de carga (passo 3) e já correr para o terminal 2 para acompanhar o atraso das mensagens (propriedade LAG).

Apesar de ter levado mais ou menos 5 minutos para processar todas as mensagens, o processamento foi feito com mensageria, dividido entre o produtor e consumidor. Com isso, podemos notar alguns benefícios como:

  • Rapidez na resposta: os usuários recebem instantaneamente a resposta de que o pix está em processamento.
  • Paralelismo: enquanto chegavam as mensagens no Apache Kafka, a outra api já ia consumindo.
  • Disponibilidade: caso a api que realiza o pix estivesse fora do ar, isso não afetaria a transação pix, pois uma vez que a mensagem estivesse armazenada no Apache Kafka, enquanto ela não for processada, ela continuará lá.

Executando a aplicação com Coroutine

Nossa aplicação já suporta totalmente mensageria. Entretanto. no pior dos casos, algum usuário só receberá a transferência depois de 5 minutos. Portanto, para melhorar esse cenário vamos executar o mesmo a passo a passo do teste anterior, só que dessa vez na Branch: feat/kafka-with-coroutine.

Repare que agora o código do nosso consumidor mudou um pouquinho do que era antes. Agora, o PixValidatorUsecase está dentro de uma função chamada de CoroutineScope. Isso fará com que o processamento seja paralelizado com coroutines.

1º passo

Primeiro, vamos limpar o terminal para baixar as novas dependências do zero. Para isso, utilize o comando:

sudo docker compose –remove-orphans

Este comando vai limpar os contêineres utilizados para o teste anterior.

Também será necessário apagar as imagens do build das apis de consumer e producer anteriores, pois queremos subir novas imagens das nossas apis com coroutines. Para isso, utilize o comando a seguir:

sudo docker images

Esse comando devolve as imagens armazenadas no Docker. Em seguida, precisamos removê-las com os comandos:

sudo docker rmi b13

sudo docker rmi eff

O comando docker rmi remove uma imagem, mas para isso é preciso informar as 3 primeiras iniciais do image Id, no caso desse teste são b13 e eff.

2º passo

Precisamos executar o docker compose com o comando abaixo:

sudo docker compose up

3º passo

Em um novo terminal, precisamos entrar no bin/bash e executar os comandos:

sudo docker exec -it pix-kafka /bin/bash

E depois, dentro do bash, executar o comando:

kafka-consumer-groups –bootstrap-server localhost:9092 –describe –all-groups

Repare que ainda está com as 14077 mensagens do teste anterior. Isso acontece porque não apagamos a imagem do Kafka e o docker compose está com volumes para container do Kafka. Os volumes garantem que os dados do Apache Kafka sejam armazenados também na máquina local e pareados no container. Entretanto, isso não é um problema. Vamos começar a contar a partir da mensagem 14078.

4º passo

Agora basta navegar até a pasta do teste de carga e executar o comando abaixo:

sudo docker compose up

Dessa vez, o teste executou 12665 vezes. Ao final do teste, se corrermos para o 2º terminal para acompanhar o atraso das mensagens, veremos que elas já foram processadas.

Elas foram processadas ao mesmo tempo que ia caindo a mensagem no Apache Kafka. Essa rapidez se dá pelo uso da coroutine no código do consumidor. Vamos executar mais uma vez nosso teste de carga para evidenciarmos mais uma vez.

Na pasta do teste de carga execute o comando:

sudo docker compose up

Repare que foram executadas 18533 requisições para transferências de pix. Ao final do teste de carga, se irmos no terminal 2 e executarmos o comando que mostra o atraso das mensagens, notaremos que todas já foram processadas instantaneamente.

Conclusão

Como vimos, o uso de uma arquitetura orientada a eventos traz muitos benefícios principalmente no processamento paralelizado, além de evitar sobrecarga de requisições e indisponibilidade da aplicação, problemas reais que podem impactar seriamente uma organização.

Nossos times solucionam este e outros desafios tecnológicos para empresas de de diversos segmentos, e que queiram mais agilidade, qualidade e alta performance em suas aplicações.

Ao contratar nossas soluções, sua empresa passa a desenvolver suas soluções tecnológicas por meio de times ágeis multidisciplinares de especialistas certificados em IA, altamente qualificados, com metodologia ágil exclusiva e infraestrutura completa.

Além disso, nossos profissionais utilizam uma solução própria de IA Generativa que integra as mais avançadas ferramentas e promove uma aceleração de todas as fases do desenvolvimento de soluções tecnológicas.

Cada time é ajustado de maneira única e conta com um estudo recorrente para construção de framework exclusivo acelerado por IA. Assim, você ganha escala de produção, segurança na alocação de especialistas e maior eficiência na distribuição de recursos mantendo qualidade de entrega e alta performance tecnológica.

Garanta resultados excepcionais com nossa abordagem acelerada e especializada! Então, conheça as soluções da Exactaworks e fale com um especialista!

Texto: David Chaves Ferreira

Edição e revisão: Priscila Jansen


    Descubra mais sobre Blog Exactaworks

    Assine agora mesmo para continuar lendo e ter acesso ao arquivo completo.

    Continue reading