Entendendo o Apache Kafka II

No meu artigo anterior expliquei um pouco sobre o funcionamento básico dos tópicos, partições e fatores de replicação. Neste artigo vou abordar modos de entrega de mensagens e grupos de consumidores.

Como explicado antes, cada partição de um tópico é gerenciada por apenas 1 broker líder. Este broker é o responsável por escrever as mensagens na partição, sendo os outros brokers responsáveis por realizar a sincronização destas mensagens para suas partições de réplica.

Esse mecanismo é abstraído pelo Kafka, assim um produtor só necessita ter uma conexão no cluster e saber o nome do tópico para o qual deseja produzir suas mensagens.

O produtor pode especificar qual o modo de entrega que deseja utilizar. O modo de entrega nada mais é do que a maneira que é feito o acknowledgement da mensagem. Existem 3 configurações possíveis:

Acks = 0

Em Acks=0, o produtor não aguarda nenhum tipo de resposta do cluster. É o modo com throughput mais elevado. É importante levar em conta que nesse modo a perda de dados é possível uma vez que o produtor não aguarda nenhum tipo de sinal do cluster.

Acks = 1

Em Acks=1, o produtor aguarda por um ok do líder da partição. Sendo assim sabemos que ao menos 1 broker recebeu a mensagem. Já é uma configuração bem mais segura que Acks=0, mas não é 100% segura uma vez que o broker líder pode cair antes que a replicação seja realizada, e o produtor não seria notificado nesse cenário.

Acks=all

Em Acks=all, o produtor aguarda o retorno até que o líder e todas as réplicas recebam a mensagem. É o modo mais seguro, mas lembre-se que para funcionar o tópico precisa ter um fator de replicação maior que 1 e o cluster deve ter mais de 1 broker. Não existe failover com apenas 1 nó, não é amiguinhos?


Consumidores: Funcionamento e modos de entrega

Vamos dar uma olhada no funcionamento de entrega de mensagens no Kafka. Quando um consumidor se conecta à um tópico, o Kafka gerencia quais mensagens deve puxar e enviar ao consumidor atual.

É aí que entra uma pegadinha: O Kafka envia as mensagens das diferentes partições em paralelo, respeitando a ordem da partição (offset).

Se você leu o primeiro artigo, sabe que o offset serve apenas para determinar a ordem da mensagem dentro da partição, e não no tópico. Trocando em miúdos, a ordem em que as mensagens são consumidas pode não ser a mesma na que elas foram produzidas.

Mensagens chegando de partições diferentes em paralelo

Internamente no Kafka, consumidores são organizados em grupos. Com esse mecanismo, o cluster consegue gerenciar qual o offset atual de leitura de cada consumidor. A atualização desses offsets de leitura é realizada pelos consumidores. Eles são responsáveis por informar ao Kafka quando leram uma mensagem e que desejam receber mais (obviamente, tudo isso já é tratado nas bibliotecas do Kafka e não exige controle manual).

Isso permite ao consumidor especificar de qual ponto ele deseja receber as mensagens de um tópico, sendo possível receber:

  • Desde o início do tópico (lembrem-se que por padrão, quando uma mensagem é gerada, ela é persistida por 2 semanas);
  • Mensagens geradas no tópico à partir do momento que o consumidor se conectou;
  • Mensagens à partir do último offset salvo para o seu grupo.

Quando vários consumidores se conectam à um tópico passando o mesmo identificador de grupo, o Kafka facilita o paralelismo enviando mensagens de partições excludentes aos consumidores, como na imagem abaixo:

Distribuição de partições com grupos de consumidores

Percebam na imagem acima o grupo 1, composto por 2 consumidores. Como o tópico AAA possui 2 partições, cada consumidor recebeu mensagens de uma partição diferente. Já no grupo 2 que possui apenas 1 único consumidor, as partições foram entregues em paralelo ao mesmo consumidor.

Aqui fica uma dica muito importante sobre o Kafka: não adianta ter mais consumidores do que partições. Caso o grupo 1 possuísse 5 consumidores, 3 deles ficariam ociosos pois o Kafka não conseguiria mandar mensagens de uma mesma partição à mais de um consumidor do mesmo grupo.

Estratégias de commit de offsets

Como dito anteriormente, os consumidores decidem quando avisar os offsets lidos para o Kafka. E cada consumidor pode selecionar entre 3 configurações sobre o commit de offsets:

At most once

Neste modo, o consumidor commita o offset para o Kafka assim que recebe a mensagem.

Este cenário possui o throughput mais elevado mas pode haver perda de dados. Como o offset é commitado antes da mensagem ser processada, se por acaso o processo do consumidor morrer, ao se reconectar ao cluster o offset da mensagem que estava sendo processada já foi commitada, e o Kafka entregará a mensagem seguinte.

Simplificando: Mensagens podem ser perdidas, mas nunca processadas com duplicação.

At least once

Neste modo, o offset é commitado após o processamento da mensagem. Se houver um erro durante o processamento, o offset não é commitado e a mensagem será processada novamente.

Este tipo de configuração funciona muito bem em conjunto com um filtro de idempotência nos consumidores.

Simplificando: Mensagens nunca serão perdidas, mas podem ser processadas com duplicação.

Exactly once

Nesse modo, uma mensagem tem a garantia de ser enviada uma única vez para um determinado consumidor. Para isso o Kafka utiliza alguns conceitos de transações na escrita de mensagens e no commit de offsets. Parece simples mas exige mecanismos de controle na parte do cliente também, não só no Kafka.


E é isso, agora vocês já possuem um conhecimento teórico legal sobre o funcionamento do Kafka. Espero que toda essa teoria acabe sendo útil à vocês no futuro.

Nos vemos em breve ;)

Like what you read? Give Leonardo Mello Gaona a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.