Um mergulho profundo em um sistema que serve como o coração da arquitetura de muitas empresas

Diego Telles
16 min readFeb 3, 2020

Antes de tudo, quero dizer que esse artigo é uma tradução do conteúdo do Stanislav Kozlovski, deixo aqui o link original do artigo.

Alguns dos monólitos que usam Apache Kafka

Introdução

Kafka é uma palavra que é ouvida muito hoje em dia … Muitas empresas digitais líderes parecem usá-lo também. Mas o que é realmente?

O Kafka foi originalmente desenvolvido no LinkedIn em 2011 e melhorou muito desde então. Atualmente, é uma plataforma inteira, permitindo armazenar redundantemente quantidades absurdas de dados, ter um barramento de mensagens com enorme taxa de transferência (milhões / s) e usar o processamento de fluxo em tempo real nos dados que passam por tudo de uma só vez.

Tudo isso é ótimo, mas despojado, o Kafka é um log de confirmação distribuído, escalável horizontalmente e tolerante a falhas.

Essas foram algumas palavras bonitas, vamos examiná-las uma a uma e ver o que elas significam. Depois, vamos nos aprofundar em como funciona.

Distribuído

Um sistema distribuído é aquele que é dividido em várias máquinas em execução, todas trabalhando juntas em um cluster para aparecer como um único nó para o usuário final. O Kafka é distribuído no sentido em que armazena, recebe e envia mensagens em diferentes nós (chamados intermediários).

Eu tenho uma introdução completa sobre isso também

Os benefícios dessa abordagem são alta escalabilidade e tolerância a falhas.

Escalonável horizontalmente

Vamos definir o termo escalabilidade vertical primeiro. Digamos, por exemplo, você tem um servidor de banco de dados tradicional que está começando a ficar sobrecarregado. A maneira de resolver isso é simplesmente aumentar os recursos (CPU, RAM, SSD) no servidor. Isso é chamado de escala vertical — onde você adiciona mais recursos à máquina. Existem duas grandes desvantagens na expansão para cima:

  1. Existem limites definidos pelo hardware. Você não pode aumentar para cima indefinidamente.
  2. Geralmente, requer tempo de inatividade, algo que as grandes empresas não podem pagar.

A escalabilidade horizontal está resolvendo o mesmo problema, lançando mais máquinas nele. A adição de uma nova máquina não exige tempo de inatividade nem há limites para a quantidade de máquinas que você pode ter em seu cluster. O problema é que nem todos os sistemas oferecem suporte à escalabilidade horizontal, pois não foram projetados para funcionar em um cluster e aqueles geralmente mais complexos para trabalhar.

A escala horizontal fica muito mais barata após um certo limite

Tolerante a falhas

Algo que surge em sistemas não distribuídos é que eles têm um único ponto de falha (SPoF). Se o seu servidor de banco de dados único falhar (como as máquinas) por qualquer motivo, você está ferrado.

Os sistemas distribuídos são projetados de maneira a acomodar falhas de maneira configurável. Em um cluster Kafka de 5 nós, você pode continuar trabalhando mesmo se dois dos nós estiverem inativos. Vale a pena notar que a tolerância a falhas está em uma troca direta com o desempenho, pois quanto mais tolerante a falhas for o seu sistema, menos desempenho ele terá.

Confirmar log

Um log de confirmação (também conhecido como log de gravação antecipada, log de transações) é uma estrutura de dados ordenada persistente que suporta apenas anexos. Você não pode modificar nem excluir registros dele. É lido da esquerda para a direita e garante a ordem dos itens.

Ilustração de amostra de um log de confirmação, tirada daqui

- Você está me dizendo que Kafka é uma estrutura de dados tão simples?

De várias maneiras, sim. Essa estrutura está no coração de Kafka e é inestimável, pois fornece pedidos, que, por sua vez, fornecem processamento determinístico. Ambos são problemas não triviais em sistemas distribuídos.

Na verdade, o Kafka armazena todas as suas mensagens no disco (mais sobre isso mais tarde), e solicitá-las na estrutura permite tirar proveito das leituras seqüenciais do disco.

  • As leituras e gravações são um tempo constante O (1) (sabendo o ID do registro) , o que, comparado às operações O (log N) de outra estrutura no disco, é uma grande vantagem, pois cada busca de disco é cara.
  • Leituras e gravações não afetam outras. A escrita não trava a leitura e vice-versa (ao contrário de árvores balanceadas)

Esses dois pontos têm enormes benefícios de desempenho, pois o tamanho dos dados é completamente dissociado do desempenho. O Kafka tem o mesmo desempenho, se você possui 100 KB ou 100 TB de dados no servidor.

Como funciona?

Os aplicativos ( produtores ) enviam mensagens ( registros ) para um nó Kafka ( broker ) e essas mensagens são processadas por outros aplicativos chamados consumidores . As mensagens são armazenadas em um tópico e os consumidores se inscrevem no tópico para receber novas mensagens.

Como os tópicos podem ficar grandes, eles são divididos em partições de tamanho menor para melhor desempenho e escalabilidade. (por exemplo: digamos que você estava armazenando solicitações de login do usuário, é possível dividi-las pelo primeiro caractere do nome de usuário do usuário)
Kafka garante que todas as mensagens dentro de uma partição sejam ordenadas na sequência em que foram recebidas. A maneira como você distingue uma mensagem específica seu deslocamento , que você pode considerar um índice de matriz normal, um número de sequência que é incrementado para cada nova mensagem em uma partição.

Kafka segue o princípio de um corretor burro e consumidor inteligente. Isso significa que o Kafka não controla quais registros são lidos pelo consumidor e os exclui, mas os armazena por um período de tempo definido (por exemplo, um dia) ou até que algum limite de tamanho seja atingido. Os próprios consumidores consultam Kafka em busca de novas mensagens e dizem quais registros querem ler. Isso permite que eles aumentem / diminuam o deslocamento em que estão, como desejam, podendo assim reproduzir e reprocessar eventos.

Vale a pena notar que os consumidores são realmente grupos de consumidores que possuem um ou mais processos de consumo. Para evitar que dois processos leiam a mesma mensagem duas vezes, cada partição está vinculada a apenas um processo do consumidor por grupo.

Representação do fluxo de dados

Persistência no disco

Como mencionei anteriormente, o Kafka realmente armazena todos os seus registros em disco e não mantém nada na RAM. Você pode estar se perguntando como isso é, no mínimo, uma escolha sensata. Existem inúmeras otimizações por trás disso que tornam viável:

  1. Kafka tem um protocolo que agrupa mensagens. Isso permite que as solicitações de rede agrupem mensagens e reduzam a sobrecarga da rede, o servidor, por sua vez, persiste em um bloco de mensagens de uma só vez e o consumidor busca grandes blocos lineares de uma só vez
  2. As leituras / gravações lineares em um disco são rápidas. O conceito de que os discos modernos são lentos é por causa de inúmeras pesquisas de disco, algo que não é um problema em grandes operações lineares.
  3. Essas operações lineares são altamente otimizadas pelo sistema operacional, por meio de técnicas de leitura antecipada (pré — busca de grandes blocos grandes) e write-behind (agrupe pequenas gravações lógicas em grandes gravações físicas).
  4. Os sistemas operacionais modernos armazenam em cache o disco na RAM livre. Isso é chamado pagecache .
  5. Como o Kafka armazena mensagens em um formato binário padronizado sem modificação em todo o fluxo (produtor-> intermediário-> consumidor) , ele pode fazer uso da otimização de cópia zero . É quando o sistema operacional copia dados do pagecache diretamente para um soquete, ignorando efetivamente o aplicativo broker Kafka.

Todas essas otimizações permitem que o Kafka entregue mensagens na velocidade da rede próxima.

Distribuição e replicação de dados

Vamos falar sobre como o Kafka atinge a tolerância a falhas e como distribui dados entre os nós.

Replicação de Dados

Os dados da partição são replicados entre vários intermediários, a fim de preservar os dados, caso um deles morra.

A qualquer momento, um broker “possui” uma partição e é o nó através do qual os aplicativos gravam / leem da partição. Isso é chamado de líder de partição . Ele replica os dados que recebe para N outros corretores, chamados seguidores . Eles armazenam os dados também e estão prontos para serem eleitos líderes, caso o nó líder morra.

Isso ajuda a configurar a garantia de que nenhuma mensagem publicada com êxito será perdida. A opção de alterar o fator de replicação permite trocar o desempenho por garantias mais duráveis ​​de durabilidade, dependendo da criticidade dos dados.

4 corretores Kafka com um fator de replicação de 3

Dessa maneira, se um líder falhar, um seguidor poderá tomar seu lugar.

Você pode estar perguntando, no entanto:

- Como um produtor / consumidor sabe quem é o líder de uma partição?

Para um produtor / consumidor escrever / ler de uma partição, eles precisam conhecer seu líder, certo? Esta informação precisa estar disponível em algum lugar.
Kafka armazena esses metadados em um serviço chamado Zookeeper .

O que é o tratador?

O Zookeeper é um armazenamento de valores-chave distribuído. É altamente otimizado para leituras, mas as gravações são mais lentas. É mais comumente usado para armazenar metadados e manipular a mecânica do cluster (pulsações, distribuir atualizações / configurações, etc.).

Ele permite que os clientes do serviço (os corretores Kafka) se inscrevam e recebam as alterações depois que elas acontecem. É assim que os corretores sabem quando trocar os líderes de partição. O tratador de zangões também é extremamente tolerante a falhas e deve ser, pois o Kafka depende muito disso.

É usado para armazenar todos os tipos de metadados, para mencionar alguns:

  • Deslocamento do grupo de consumidores por partição (embora os clientes modernos armazenem compensações em um tópico Kafka separado)
  • ACL (Access Control Lists) — usada para limitar o acesso / autorização
  • Cotas de produtores e consumidores — limite máximo de mensagens / s
  • Líderes de partição e sua saúde

Como um produtor / consumidor sabe quem é o líder de uma partição?

Produtores e consumidores costumavam se conectar e conversar diretamente com o Zookeeper para obter essas (e outras) informações. A Kafka está se afastando desse acoplamento e, desde as versões 0.8 e 0.9, respectivamente, os clientes buscam informações de metadados diretamente dos corretores Kafka, que conversam com o Zookeeper.

Fluxo de metadados

Transmissão

No Kafka, um processador de fluxo é qualquer coisa que pega fluxos contínuos de dados dos tópicos de entrada, realiza algum processamento nessa entrada e produz um fluxo de dados para tópicos de saída (ou serviços externos, bancos de dados, lixeira, onde quer que seja …)

É possível fazer um processamento simples diretamente com as APIs de produtor / consumidor; no entanto, para transformações mais complexas, como unir fluxos juntos, o Kafka fornece uma biblioteca integrada de APIs do Streams .

Esta API deve ser usada em sua própria base de código, não está sendo executada em um broker. Funciona de maneira semelhante à API do consumidor e ajuda a expandir o trabalho de processamento de fluxo em vários aplicativos (semelhantes aos grupos de consumidores).

Processamento sem estado

Um processamento sem estado de um fluxo é um processamento determinístico que não depende de nada externo. Você sabe que, para qualquer dado, você sempre produzirá a mesma saída independentemente de qualquer outra coisa. Um exemplo disso seria a simples transformação de dados — acrescentando algo a uma string "Hello"-> "Hello, World!".

Dualidade de tabela de fluxo

É importante reconhecer que fluxos e tabelas são essencialmente os mesmos. Um fluxo pode ser interpretado como uma tabela e uma tabela pode ser interpretada como um fluxo.

Fluxo como uma tabela

Um fluxo pode ser interpretado como uma série de atualizações de dados, nas quais o agregado é o resultado final da tabela. Essa técnica é chamada de Event Sourcing .

Se você observar como a replicação síncrona do banco de dados é alcançada, verá que é através da chamada replicação de streaming , onde cada alteração em uma tabela é enviada para um servidor de réplica. Outro exemplo de fornecimento de eventos são os livros contábeis Blockchain — um livro contábil também é uma série de mudanças.

Um fluxo Kafka pode ser interpretado da mesma maneira — eventos que, quando acumulados, formam o estado final. Essas agregações de fluxo são salvas em um RocksDB local (por padrão) e são chamadas de KTable.

Cada registro incrementa a contagem agregada

Tabela como um fluxo

Uma tabela pode ser vista como uma captura instantânea do valor mais recente para cada chave em um fluxo. Da mesma maneira que os registros de fluxo podem produzir uma tabela, as atualizações de tabela podem produzir um fluxo de registro de alterações.

Cada atualização produz um registro de captura instantânea no fluxo

Processamento com estado

Algumas operações simples como map()ou filter()são apátridas e não exigem que você mantenha nenhum dado referente ao processamento. No entanto, na vida real, a maioria das operações que você fará será com estado (por exemplo count()) e, como tal, exigirá que você armazene o estado atualmente acumulado.

O problema com a manutenção do estado nos processadores de fluxo é que eles podem falhar! Onde você precisaria manter esse estado para ser tolerante a falhas?

Uma abordagem ingênua é simplesmente armazenar todos os estados em um banco de dados remoto e ingressar na rede nesse armazenamento. O problema é que não há localidade de dados e muitas viagens de ida e volta à rede, o que reduz a velocidade do aplicativo. Um problema mais sutil, mas importante, é que o tempo de atividade da sua tarefa de processamento de fluxo seria fortemente acoplado ao banco de dados remoto e a tarefa não será independente (uma alteração no banco de dados de outra equipe pode interromper o processamento) .

Então, qual é a melhor abordagem?
Lembre-se da dualidade de tabelas e fluxos. Isso nos permite converter fluxos em tabelas que são co-localizadas com nosso processamento. Ele também fornece um mecanismo para lidar com a tolerância a falhas — armazenando os fluxos em um broker Kafka.

Um processador de fluxo pode manter seu estado em uma tabela local (por exemplo, RocksDB), que será atualizada a partir de um fluxo de entrada (após talvez alguma transformação arbitrária). Quando o processo falha, ele pode restaurar seus dados, reproduzindo o fluxo.

Você pode até ter um banco de dados remoto como o produtor do fluxo, transmitindo efetivamente um changelog com o qual você reconstrói a tabela localmente.

Processamento com estado, juntando um KStream a um KTable

KSQL

Normalmente, você seria obrigado a gravar o processamento do fluxo em um idioma da JVM, pois é aí que está o único cliente oficial da API do Kafka Streams.

Configuração de amostra do KSQL

Lançado em abril de 2018 , o KSQL é um recurso que permite gravar seus trabalhos simples de streaming em uma linguagem familiar semelhante ao SQL.

Você configura um servidor KSQL e o consulta interativamente por meio de uma CLI para gerenciar o processamento. Ele funciona com as mesmas abstrações (KStream e KTable), garante os mesmos benefícios da API do Streams (escalabilidade, tolerância a falhas) e simplifica bastante o trabalho com fluxos.

Isso pode não parecer muito, mas na prática é muito mais útil para testar coisas e até permite que pessoas fora do desenvolvimento (por exemplo, proprietários de produtos) brincem com o processamento de fluxo. Convido você a dar uma olhada no vídeo de início rápido e ver como é simples .

Alternativas de streaming

Os fluxos Kafka são uma mistura perfeita de potência e simplicidade. Sem dúvida, possui as melhores capacidades para trabalhos de fluxo no mercado e se integra com o Kafka de maneira mais fácil do que outras alternativas de processamento de fluxo ( Storm , Samza , Spark , Wallaroo ).

O problema com a maioria das outras estruturas de processamento de fluxo é que elas são complexas para trabalhar e implantar. Uma estrutura de processamento em lote como o Spark precisa:

  • Controle um grande número de tarefas em um conjunto de máquinas e distribua-as eficientemente pelo cluster.
  • Para isso, é necessário empacotar dinamicamente seu código e implantá-lo fisicamente nos nós que o executarão. (junto com a configuração, bibliotecas, etc.)

Infelizmente, resolver esses problemas torna as estruturas bastante invasivas. Eles desejam controlar muitos aspectos de como o código é implantado, configurado, monitorado e empacotado.

O Kafka Streams permite implementar sua própria estratégia de implantação quando você precisar, seja Kubernetes , Mesos , Nomad , Docker Swarm ou outros.

A motivação subjacente do Kafka Streams é permitir que todos os seus aplicativos executem o processamento do fluxo sem a complexidade operacional de executar e manter outro cluster. A única desvantagem potencial é que ele está fortemente associado ao Kafka, mas no mundo moderno, onde a maioria, se não todo o processamento em tempo real, é alimentado pelo Kafka, o que pode não ser uma grande desvantagem.

Quando você usaria Kafka?

Como já falamos, o Kafka permite que você receba uma quantidade enorme de mensagens em uma mídia centralizada e as armazene sem se preocupar com coisas como desempenho ou perda de dados.

Isso significa que ele é perfeito para ser usado como o coração da arquitetura do seu sistema, atuando como um meio centralizado que conecta diferentes aplicativos. O Kafka pode ser a peça central de uma arquitetura orientada a eventos e permite que você realmente separe os aplicativos um do outro.

O Kafka permite dissociar facilmente a comunicação entre diferentes (micro) serviços. Com a API do Streams, agora é mais fácil do que nunca escrever uma lógica de negócios que enriquece os dados do tópico Kafka para consumo de serviço. As possibilidades são enormes e peço que você explore como as empresas estão usando o Kafka.

Por que tem visto tanto uso?

Alto desempenho, disponibilidade e escalabilidade por si só não são motivos fortes o suficiente para uma empresa adotar uma nova tecnologia. Existem outros sistemas que possuem propriedades semelhantes, mas nenhum se tornou tão amplamente utilizado. Por que é que?

A razão pela qual Kafka cresceu em popularidade (e continua a fazê-lo) é uma coisa importante — as empresas hoje em dia se beneficiam muito da arquitetura orientada a eventos. Isso ocorre porque o mundo mudou — uma quantidade enorme (e crescente) de dados está sendo produzida e consumida por muitos serviços diferentes (Internet das Coisas, Machine Learning, Mobile, Microservices).

Uma única plataforma de transmissão de eventos em tempo real com armazenamento durável é a maneira mais limpa de alcançar essa arquitetura. Imagine que tipo de confusão seria se a transmissão de dados de / para cada serviço usasse uma tecnologia diferente especificamente criada para ele.

Isso, combinado com o fato de o Kafka fornecer as características apropriadas para um sistema tão generalizado (armazenamento durável, transmissão de eventos, primitivas de tabela e fluxo, abstração via KSQL, código aberto, desenvolvido ativamente), faz dele uma escolha óbvia para as empresas.

Sumário

O Apache Kafka é uma plataforma de streaming distribuída capaz de lidar com trilhões de eventos por dia. O Kafka fornece pipelines de publicação e assinatura com baixa latência, alta taxa de transferência e tolerância a falhas e é capaz de processar fluxos de eventos.

Examinamos sua semântica básica (produtor, corretor, consumidor, tópico), aprendemos sobre algumas de suas otimizações (pagecache), aprendemos como é tolerante a falhas replicando dados e fomos apresentados a suas poderosas capacidades de streaming em constante crescimento.

Kafka teve uma grande adoção em milhares de empresas em todo o mundo, incluindo um terço das empresas listadas na Fortune 500. Com o desenvolvimento ativo do Kafka e a primeira versão principal 1.0, lançada recentemente (1 de novembro de 2017), há previsões de que essa plataforma de streaming irá ser tão grande e central de uma plataforma de dados quanto os bancos de dados relacionais.

Espero que esta introdução tenha ajudado a familiarizá-lo com o Apache Kafka e seu potencial.

Recursos e coisas de leitura adicionais que não mencionei

A toca do coelho é mais profunda do que este artigo foi capaz de cobrir. Aqui estão alguns recursos que não tive a chance de mencionar, mas que são importantes:

Controller Broker, réplicas em sincronização — A maneira pela qual o Kafka mantém o cluster íntegro e garante consistência e durabilidade adequadas.

API do conector — API que ajuda a conectar vários serviços ao Kafka como fonte ou coletor (PostgreSQL, Redis, ElasticSearch)

Compactação de log — uma otimização que reduz o tamanho do log. Extremamente útil em fluxos de changelog

Semântica de mensagens exatamente uma vez — garanta que as mensagens sejam recebidas exatamente uma vez. Este é um grande negócio, pois é difícil de alcançar.

Recursos

Sapador-bombeiro de sistemas distribuídos do Apache Kafka — o Controller Broker — Outro post meu no qual eu explico como a coordenação entre o broker funciona e muito mais.

Blog Confluent — uma riqueza de informações sobre o Apache Kafka

Documentação Kafkadocumentação excelente, extensa e de alta qualidade

Kafka Summit 2017 vídeos

Obrigado por separar um tempo para ler isso.

Se você acha que essa informação foi útil, considere dar-lhe uma quantidade considerável de palmas para aumentar sua visibilidade e ajudar as novas pessoas a encontrá-la!

~ Stanislav Kozlovski

Atualizar

Este artigo abriu a porta para eu me juntar ao Confluent . Sou imensamente grato pela oportunidade que eles me deram — atualmente trabalho no próprio Kafka, o que é incrível! Confluent é uma empresa de big data fundada pelos próprios criadores do Apache Kafka! Atualmente, trabalhamos em todo o ecossistema Kafka, incluindo uma oferta de nuvem gerenciada Kafka como serviço.

Estamos contratando muitas posições (especialmente SRE / Software Engineers) na Europa e nos EUA! Se você estiver interessado em trabalhar no próprio Kafka, procurando novas oportunidades ou simplesmente curioso — certifique-se de me enviar uma mensagem no Twitter e compartilharei todas as grandes vantagens que advêm do trabalho em uma empresa da área da baía.

--

--

Diego Telles

AWS Community Builder | Tech Manager | Front-end | Mozillian Member 🦊| Subscribe: youtube.com/UnicornCoder