1. Introdução ao Apache Kafka
O Apache Kafka é uma plataforma de streaming distribuída que é usada para construir pipelines de dados em tempo real e aplicativos de streaming. É um sistema de mensagens de alto desempenho e baixa latência que é projetado para lidar com grandes volumes de dados e permitir a troca de dados em tempo real entre aplicativos.
O Apache Kafka foi originalmente desenvolvido pelo LinkedIn e, posteriormente, foi doado para a Apache Software Foundation. Ele é escrito em Java e é uma plataforma de código aberto que pode ser executada em uma variedade de sistemas operacionais, incluindo Linux, macOS e Windows.
A plataforma é frequentemente usada em casos de uso como análise de dados em tempo real, processamento de stream, integração de sistemas, agregação de logs e métricas, entre outros.
O Kafka é baseado em uma arquitetura distribuída, o que significa que ele é capaz de escalar horizontalmente e lidar com grandes quantidades de dados em tempo real. É também altamente tolerante a falhas, com recursos de replicação e failover integrados.
Em resumo, o Apache Kafka é uma plataforma de streaming distribuída que oferece alta escalabilidade, baixa latência e tolerância a falhas para casos de uso de streaming de dados em tempo real.
2. Partes que compõem o Apache Kafka
O Apache Kafka é composto por várias partes que trabalham juntas para fornecer um pipeline de dados escalável e de baixa latência para processamento e transmissão de dados em tempo real. Essas partes incluem produtores, consumidores, tópicos, partições, brokers, ZooKeeper e grupos de consumidores.
fig. 1 - arquitetura do kafka
Cada uma dessas partes tem um papel importante no funcionamento do Kafka e na entrega dos dados de forma eficiente e confiável.
-
Producers: são responsáveis por enviar dados para o Kafka. Eles produzem os dados e os enviam para um ou mais tópicos do Kafka.
-
Consumers: são responsáveis por receber dados do Kafka. Eles se inscrevem em um ou mais tópicos e consomem os dados produzidos pelos produtores.
-
Consumers Groups: são grupos de consumidores que compartilham a carga de leitura de partições de um tópico. O objetivo é permitir que os consumidores possam se balancear e escalonar horizontalmente conforme necessário.
-
Topics: são fluxos de dados semelhantes a uma categoria ou um feed de notícias. Eles representam as categorias ou áreas de interesse dos dados no Kafka.
-
Partitions: são divisões lógicas de um tópico no Kafka. Elas são usadas para distribuir e paralelizar o processamento de dados em vários nós do Kafka Cluster.
-
Brokers: são os nós do Kafka Cluster que armazenam e distribuem as partições do tópico em diferentes nós do cluster. Cada nó do Kafka é um broker que executa uma ou mais instâncias do Kafka.
-
ZooKeeper(Opcional): é um serviço de coordenação distribuída que é usado para gerenciar e manter a configuração do Kafka Cluster. O ZooKeeper é responsável por armazenar informações de configuração, monitorar a disponibilidade dos nós do Kafka e coordenar o processo de failover.
No geral, todas essas partes trabalham juntas para criar um sistema distribuído de streaming de dados que pode lidar com grandes volumes de dados em tempo real, oferecendo alta escalabilidade, baixa latência e tolerância a falhas.
3. Tópicos e Partições no Apache Kafka
De forma geral, o Kafka armazena registros em tópicos. Portanto, quando enviamos um novo registro para o Kafka, devemos decidir o nome do tópico para onde ele deve ser armazenado. Também, devmos fornecer o nome de um tópico para receber e processar registros do Kafka.
Quando falmos de registros, eventos, mensagens estamos essencialmente falando da mesma informação. No decorrer deste post iremos chamar as informações enviadas e coletadas dos tópicos de mensagens.
Pense nos tópicos como a fila ou tabela em que você deseja armazenar seus dados. Gostei bastante da comparação entre tópicos e tabelas de banco de dados feita nesta apresentação de Robin Moffatt. Por exemplo, você tem um tópico que contém pedidos, o que é bastante razoável para comparar com uma tabela de banco de dados que contém informações de pedidos. Suas aplicações podem, então, usar este tópico para enviar informações sobre pedidos conforme eles chegam enquanto serviços downstream os processam.
Na terminologia do Kafka, os produtores
enviam novas mensagens, enquanto os consumidores
as lêem mais tarde (embora possivelmente quase instantaneamente). Os tópicos
conectam produtores
e consumidores
criando uma ponte entre eles.
fig. 2 - fluxo de comunicação entre produtores, tópicos e consumidores
Um tópico
é uma uma categoria para as mensagens que estão sendo transmitidas. Cada informação é associada a um tópico
específico, que é definido por um nome. Quando um produtor
envia uma mensagem, ele especifica o nome do tópico
ao qual essa mensagem está relacionada.
Por sua vez, os consumidores
podem se inscrever em um ou mais tópicos
, de acordo com seus interesses. Isso significa que eles receberão apenas as mensagens que estão relacionadas aos tópicos
nos quais se inscreveram. Por exemplo, na imagem a seguir percebemos que os consumidores
se conectaram apenas ao tópico
ORDERS.
fig. 3 - fluxo de comunicação entre produtores, tópicos e consumidores no detalhe
Embora as duas imagens anteriores descrevam bem o que são tópicos
, elas fornecem apenas uma visão geral. Para compreender melhor o funcionamento de um tópico, é necessário investigar mais a fundo.
Um tópico
é constituido por multiplas queues internas
chamadas de partições
, que armazenam as mensagens enviadas para o Kafka. Por exemplo:
fig. 3 - organização de partições dentro do tópico
Cada partição
em um tópico
mantém sua própria ordem, o que é fundamental para a escalabilidade do Kafka. Os produtores
podem enviar mensagens para qualquer partição
em um tópico
, escolhendo uma partição
com base na chave da mensagem
ou especificando explicitamente uma partição
. Esse método de divisão de mensagens permite que cada partição
cresça em ritmos semelhantes.
Ao se inscrever em um tópico
, os consumidores
são designados para receber mensagens de algumas das partições
desse tópico
.
Cada consumidor
recebe mensagens de uma partição
que mantém a ordem em que foram produzidos. Essa ordem possibilita o uso de vários consumidores
para processar eventos de um único tópico
, o que melhora o desempenho e a disponibilidade (desde que implementado corretamente).
fig. 4 - diagrama completo de comunicação entre produtores, tópicos e consumidores
4. Produtores e Consumidores no Apache Kafka
Os produtores
são responsáveis por gerar o código do cliente Kafka, este por sua vez é utilizado para enviar as mensagens para os tópicos
.
Esses clientes diminuem significativamente a complexidade de uso do Kafka, já que eles lidam com problemas como pooling de conexões e buffer de rede. Com isso, é possível interagir com o Kafka fazendo uso de uma pequena quantidade de APIs.
Em artigos futuros iremos utilizar o Java para implementar os
produtores
econsumidores
.
O diagrama a seguir ilustra como um produtor
envia uma mensagem para um broker
, que, por sua vez, o registra em uma das partições
dos tópicos
.
fig. 5 - diagrama de comunicação entre produtor, broker e tópico
Os consumidores
são responsáveis por gerar o código do cliente Kafka para ler as mensagens
dos tópicos
, atuando na extremidade oposta em relação aos produtores
e aproveitando as mesmas funcionalidades, como pooling de conexões e buffer de rede.
O diagrama abaixo exemplifica a interação entre um consumidor
e um broker
, em que o consumidor
recebe as mensagens armazenadas em um tópico
.
fig. 6 - diagrama de comunicação entre consumidor, broker e tópico
5. Offset no Apache Kafka
Cada mensagem armazenada em uma partição
tem a ela atribuída um offset
que indica a distância dela em relação ao início da partição
.
Adicionar novas mensagens aumenta o offset
, garantindo que as mensagens mais recentes sempre terão um offset
maior do que as mensagens mais antigos (com base no tempo em que foram armazenadas).
fig. 7 - atribuição de offset em uma partição
Os offsets
não tão importantes ao se persistir novas mensagens, pois essa parte é toda tratada pelo Kafka. No entanto, o conceito desempenha um papel importante ao consumir as mensagens.
Os consumidores
usam offsets
das partições
para acompanhar quais mensagens foram processadas. À medida que ele busca mensagens e realiza o processamento necessário, precisa de alguma formar marcar os offsets
dessas mensagens, para que o consumidor
saiba de qual ponto deve retomar a busca por mensagens em caso de falhas.
5.1 Commit dos offsets
O processo de acompanhamento dos offsets
de um consumidor
é conhecido como commit. Isso significa que o offset
atual de uma partição
é "commitado" e armazenado.
O consumidor
não armazena seus offsets
localmente. Em vez disso, ele os envia para o broker
do Kafka, que os persiste em disco.
Ao manter os offsets
remotamente no broker
, reduzimos o acoplamento entre os clientes consumidores
dentro do contexto da nossa aplicação. Desta forma é possível iniciar, parar e até mesmo destruir as máquinas que executam os consumidores
sem impedir a recuperação da nossa aplicação.
É possível inicializar um novo cliente consumidor
e continuar instantaneamente o processamento a partir do ponto em que o consumidor
anterior parou.
6. Consumer Groups, agrupamento de consumidores
Os consumidores
podem se agrupar em “grupos de consumidores”, que determinam quais mensagens cada um receberá. Embora isso possa parecer vago, não há outra maneira curta e sucinta de resumir este assunto.
Em resumo, os grupos de consumidores
realizam o seguinte:
- Agrupam os consumidores por função
- Compartilham as partições de um tópico entre os consumidores do mesmo grupo
Os grupos de consumidores
nos permite relacionar um conjunto de consumidores
que trabalhem juntos para executar uma única função, processo ou tarefa. Cada grupo de consumidores
processa todas mensagens de um tópico
independentemente de outros grupos.
Por exemplo, se você tiver um tópico
que represente dados de vendas, um grupo poderá manter um agregado dos valores de venda enquanto outro passa para um sistema downstream para processamento posterior.
Ambos esses grupos serão executados independentemente e gerenciarão seus offsets
, mesmo ao se inscreverem no mesmo tópico
.
O diagrama abaixo ilustra dois grupos de consumidores
que recebem todas as mensagens armazenadas no tópico
:
fig. 8 - consumidores agrupados por função
6.1 Compartilhando as partições de um tópico entre os consumidores do mesmo grupo
Cada consumidor
dentro de um grupo de consumidores
é atribuído a um conjunto de partições
de um tópico
, garantindo o compartilhamento de mensagens entre o grupo e mantendo a ordem das mensagens em cada partição
. Esse mecanismo é otimizado mantendo as atribuições de partições
iguais até a adição de um novo consumidor
ao grupo.
Nesse momento, o Kafka redistribui as partições
entre os consumidores
do grupo, um processo conhecido como “rebalanceamento”. Se houver mais partições
do que consumidores
em um grupo, os consumidores
podem ser atribuídos a várias partições
.
O diagrama ilustra o compartilhamento de partições
em um único grupo de consumidores
:
fig. 9 - compartilhamento de partições entre os consumidores
A inclusão de outro grupo de consumidores
não afeta a atribuição dos grupos existentes, como mostrado abaixo:
fig. 10 - novo grupo de consumidores não afeta a atribuição dos grupos existentes
Quando um novo consumidor
é adicionado a um grupo, o Kafka realiza um rebalanceamento. Durante esse processo, as partições
de cada tópico
atribuídas ao grupo são redistribuídas entre todos os consumidores
do grupo de maneira uniforme, garantindo que cada consumidor
tenha aproximadamente o mesmo número de partições
para consumir.
Esse processo ajuda a garantir o equilíbrio de carga entre os consumidores
do grupo e otimiza o desempenho do Kafka.
fig. 11 - redistribuição das partições entre os consumidores do grupo
7. Executando um teste com o Apache Kafka utilizando o cli
Para executarmos um teste simples rodando um broker
do kafka localmente precisaremos ter instalado o Java JDK 8 ou superior.
Realizae o download do Apache Kafka, no momento em que escrevo este artigo a versão mais recente é a 3.4.0 Scala 2.13.
Para demonstração iremos utilizar o sistema operacional Linux Ubuntu 22.04. Portanto para efetuar o download digite o comando abaixo:
$ wget https://downloads.apache.org/kafka/3.4.0/kafka_2.13-3.4.0.tgz
Depois de finalizar o download descompacte os arquivos e acesse a pasta kafka_2.13-3.4.0
com os comandos abaixo:
$ tar -xzf kafka_2.13-3.4.0.tgz
$ cd kafka_2.13-3.4.0
Agora inicialize o ZooKeeper e em seguida o Apache Kafka com os comandos abaixo:
$ ./bin/zookeeper-server-start.sh config/zookeeper.properties
$ ./bin/kafka-server-start.sh config/server.properties
fig. 12 - zookeeper e apache kafka em execução
Vamos então criar o nosso tópico
para que possamos publicar algumas mensagens e posteriormente consumir essas mensagens.
Para isso no terminal digite o comando abaixo:
$ ./bin/kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic LIKES_POST
Para verificar se o tópico foi criado com sucesso, digite o comando abaixo:
$ ./bin/kafka-topics.sh --list --bootstrap-server localhost:9092
A saída será o nome do nosso tópico
LIKES_POST.
Agora iniciamos o nosso produtor
com o comando abaixo:
$ ./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic LIKES_POST
Este comando libera a E/S para digitar as mensagens que poderão ser inseridas a cada linha, como abaixo:
>
Agora inicie o consumidor
com o comando a seguir:
$ ./bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic LIKES_POST --from-beginning
Vamos então inputar algumas mensagens e acompanhar o consumidor.
fig. 12 - interação entre produtor e consumidor
Conclusão
O Apache Kafka é uma plataforma distribuída de streaming que permite a troca de mensagens em tempo real entre aplicações de maneira escalável e confiável. Sua arquitetura distribuída garante alta disponibilidade, tolerância a falhas e escalabilidade horizontal.
Os tópicos
do Kafka permitem organizar as mensagens por assunto, permitindo que as aplicações consumidoras
obtenham as informações relevantes de acordo com sua necessidade.
Os produtores e consumidores
são responsáveis por enviar e receber as mensagens para e do Kafka, respectivamente, e os offsets
são usados pelos consumidores
para acompanhar o progresso no processamento das mensagens.
O uso de grupos de consumidores
permite agrupar consumidores
com a mesma função, compartilhar as partições
do tópico
e garantir que cada consumidor
processe uma parte exclusiva das mensagens.
Com esses conceitos em mente, é possível construir sistemas distribuídos altamente escaláveis e confiáveis usando o Apache Kafka como plataforma de streaming.
E é isso por hoje, pessoal!
Chegamos ao final de mais um artigo, espero que tenha sido útil e que você tenha aprendido algo novo.
Caso tenha alguma dúvida, comentário ou tenha encontrado algum erro, por favor, envie-me um email. Ficarei feliz em ouvir de você.
Se desejar receber novos artigos diretamente em seu e-mail, por favor, assine a nossa Newsletter. E se você já é um assinante, muito obrigado!
Aproveito e deixo um convite para nos conectarmos no Twitter e LinkedIn.
👋 Obrigado por ler até o final e até o próximo artigo !!!