Kafka
Tags: braziliandevs, microservices
Published: 2022-07-01 22:25:21

O Kafka é uma plataforma distribuída de streaming de eventos. Além disso ele é open source e utilizado por milhares de empresas.

Hoje em dia tudo é evento e o kafka nos ajuda a processar esses eventos de forma rápida, fácil e resiliente. O kafka por padrão salva os eventos que passam por ele para guardar histórico, inclusive podem ser utilizados como um storage, nesse [post do blog do linkedin](https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying) de 2013 o Jay Kreps fala uma pouco mais sobre isso (curiosidade: O Kafka nasceu no Linkedin).

## Poderes do Kafka

- Altíssimo throughput: Ele tem uma capacidade muito alta de ser bombardeado por requisições

- Latência extremamente baixa (2ms): Leva muito pouco tempo para uma informação ser trafegada nele

- Escalável

- Armazenamento

- Alta disponibilidade

- Existe driver para quase qualquer linguagem

- Bibliotecas prontas para mais diversas tecnologias

- Ferramentas open-source, ex: kafka-connect, kafka-streams, ksqldb


## Como funciona

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc74kf0a0o7h63cvb7c6.png)

A dinâmica básica é um produtor de mensagem de um lado e um consumidor dessa mensagem dos outros  porem ao invés do produtor mandar a mensagem direto para o consumidor ele enviar para o kafka (que na verdade é um cluster de brokers), e então o broker salva o valor em seu banco de dados e então o consumer acessa esse cluster e pega essa nova mensagem. Existe uma concepção errada que inclusive eu tinha de que o kafka envia a mensagem para o consumer mas na verdade o consumer que vai buscar pela mensagem.

A recomendação mínima para colocar o kafka em produção são 3 brokers, para gerenciar todas as questões com relação a esses brokers como: ver se a maquina está rodando, em qual maquina vai ser armazenado a mensagem e etc temos o apache zookeeper que também é um sistema open source da apache, porem atualmente o plano é retirar o zookeeper e deixar o kafka totalmente independente

## Tópicos
Tópico é o canal de comunicação responsável por receber e disponibilizar os dados enviados para o kafka, então quando o producer envia uma mensagem para um broker na verdade ele envia para um tópico desse broker e o consumer também lê as mensagens desse tópico. Podemos inclusive ter mais de um consumer lendo mensagens de um mesmo tópico, então podemos por exemplo ter um sistema de logs, e o sistema de evento lendo as mesmas mensagens do tópico.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l11awb1tx43p31dz7sqp.png)
Cada mensagem enviada para um tópico é armazenada uma depois da outra em ordem de chegada, para cada mensagem armazenada ela recebe um offset que é sua posição nesse array de mensagens. Dois consumers podem estar em diferentes offsets de um mesmo tópico sem problema algum

## Anatomia de uma mensagem

Uma mensagem é composta por 4 partes principais

#### 1. Headers
São dados opcionais que podemos trabalhar como se fossem metadados que podemos passar para nos ajudar

#### 2. Key
Como o nome diz é a chave da mensagem, é um conceito um pouco complicado de explicar que no começo me confundiu bastante, mas pense que ela é um parâmetro não obrigatório que podemos passar quando queremos garantir uma ordem de chegada de mensagens em um determinado contexto. Depois vou explicar com um exemplo.

#### 3. Value
Como o nome já diz é conteúdo da mensagem, os valores que enviamos naquela mensagem

#### 4. Timestamp
Marca quando a mensagem foi enviada

## Partições
Cada tópico pode ter uma ou mais partições para garantir a distribuição e resiliência dos dados. Para evitar deixar todos os dados em um mesmo broker o kafka faz varias partições para um mesmo tópico em diferentes brokers para que assim caso um broker caia não aconteça de nenhum consumer conseguir ler essas mensagens. 

Outro beneficio de aumentar as partições é que podemos ter mais de uma replica de consumer lendo de um topico cada uma pode se conectar com uma partição e ler todas as mensagens dessa partição, multiplicando assim sua velocidade.

Ex: Temos 1.000.000 de pagamentos em um tópico e apenas um serviço de processar esses pagamentos, esse serviço vai ter que então ler essas 1.000.000 mensagens para processarmos todos os pagamentos, mas e se replicarmos esse serviço? ai temos um problema de garantir que esses dois serviços não vão acabar lendo as mesmas mensagens, agora se adicionarmos mais uma partição e dividirmos 500.000 mensagens para cada, cada consumer pode se conectar em uma partição e vamos processar essas mensagens no dobro da velocidade incial

## Como funciona a Key

Vamos imaginar uma operação de compras onde a ordem é bem importante de ser mantida, então quando o cliente faz uma compra nós enviamos uma mensagem com uma key que pode ser um uuid gerado para representar essa compra, a partir de agora todas as mensagens que chegarem com essa key o kafka vai GARANTIR que vai manter a ordem de chegada mantendo essas mensagens com a mesma key na mesma partição, evitando assim de acontecer por exemplo a mensagem de emitir uma nota fiscal vir primeiro que a de aprovar pagamento. 

O consumidor que for ler a partição sempre vai pegar essas mensagens na ordem correta, diferente de se por exemplo elas estivessem em diferentes partições que não temos como garantir que um consumidor não vai consumir mais rápido que o outro gerando assim uma ordem errada de processamento

## Replication Factor e Partition Leadership
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qdl349483mmjqdozj32.png)

Trabalhando com partições já temos uma boa solução para como manter os dados distribuídos porem ainda não temos uma resiliencia total, pois se um broker cair vamos ter uma perda temporaria dos dados daquela partição o que pode ser tolerado, porem se o broker perder o hd por exemplo vamos ter uma perda definitiva daqueles dados o que não pode ser tolerado.

Podemos então utilizar o replication factor, onde informamos quantas replicas de cada partição queremos, na imagem podemos ver que temos 1 copia de cada partição e sempre essa copia em brokers diferentes, assim, caso aconteça algo com o broker 1 por exemplo ainda temos todos os dados dele replicados nos brokers 2 e 3

Sempre que replicamos as partições teremos uma partição líder e sempre que o consumidor for ler dessa partição ele vai ler também da partição líder. Somente se a partição líder cair que o Kafka vai fazer um novo sorteio e definir qual a nova partição que será a líder


## Garantia de entrega das mensagens

Quando o producer envia uma mensagem para o tópico ele pode configurar um parâmetro que é o Ack.

**Ack 0**: o producer informa que ele não precisa saber se a mensagem de fato chegou, isso também é chamado de FF: Fire and Forget onde simplesmente passamos a mensagem para o tópico sem se importar se ele recebeu ou não

**Ack 1**: o producer envia uma mensagem e espera que a partição líder responda informando que salvou a mensagem. Ainda temos o risco de perder a mensagem caso o líder caia antes de replicar as mensagens para os seus seguidores

**Ack -1**: O producer envia a mensagem, o líder salva essa mensagem, replica para os seguidores os seguidores avisam que salvaram e só então ele responde ao producer informando que salvou, é a forma de ter 100% de certeza que a mensagem foi salva

Garantias de entrega no consumer:

**At most once**: O consumer vai receber as mensagens no máximo uma vez, é a forma mais performática porem pode perder mensagens no meio do caminho

**At least once**: O consumer vai receber as mensagens pelo menos uma vez, assim é garantido que ele vai receber, tem um tempo de processamento moderado mas é preciso garantir que o consumer sabe o que fazer ao receber uma mensagem repetida

**Exactly once**: O consumer vai receber as mensagens exatamente uma vez. Essa forma tem a pior performance pois o kafka tem que garantir que o consumidor recebeu a mensagem que ele enviou e q ele ainda não recebeu a mensagem que ele vai enviar

## Consumer Group

Vamos supor um cenário com mais partições do que consumidores porem os consumidores estão em um mesmo grupo, nesse caso eles vão se dividir para ler as partições, agora vamos imaginar mais um consumidor que não está nesse mesmo grupo, esse consumidor vai ler de todas as partições. Agora se no nosso grupo tivermos mais consumers do que partições o que acontece é que esses consumers extra ficam esperando uma partição livre para que eles leiam, em um mesmo grupo nunca vai ter mais de um consumer por partição