Usando o Kafka como um Eventstore (CQRS). Boa ideia?

Embora eu tenha me deparado com Kafka antes, recentemente percebi que Kafka talvez possa ser usado como (a base de) um CQRS , eventstore .

Um dos principais pontos que Kafka suporta:

  • Captura / armazenamento de events, todas as HA, é claro.
  • Arquitetura Pub / Sub
  • Capacidade de reproduzir o log de events que permite a capacidade de novos assinantes se registrarem no sistema após o fato.

É verdade que eu não sou 100% versado em CQRS / Event sourcing, mas isso parece muito perto do que um eventstore deveria ser. O engraçado é que eu realmente não consigo encontrar muito sobre o Kafka ser usado como uma loja de events, então talvez eu devesse estar perdendo alguma coisa.

Então, falta alguma coisa de Kafka para que seja uma boa loja de events? Isso funcionaria? Usando a produção? Interessado em insight, links, etc.

Basicamente, o estado do sistema é salvo com base nas transactions / events que o sistema já recebeu, em vez de apenas salvar o estado atual / instantâneo do sistema, que é o que normalmente é feito. (Pense nisso como um livro de contabilidade geral: todas as transactions acabam chegando ao estado final) Isso permite todos os tipos de coisas legais, mas apenas leia os links fornecidos.

O Kafka é um sistema de mensagens que tem muitas semelhanças com uma loja de events, no entanto, para citar sua introdução:

O cluster Kafka retém todas as mensagens publicadas, independentemente de terem sido consumidas, por um período de tempo configurável . Por exemplo, se a retenção estiver definida para dois dias, nos dois dias após a publicação da mensagem, ela ficará disponível para consumo, após o que ela será descartada para liberar espaço. O desempenho de Kafka é efetivamente constante em relação ao tamanho dos dados, portanto não é um problema reter muitos dados.

Portanto, embora as mensagens possam ser retidas indefinidamente, a expectativa é que elas sejam excluídas. Isso não significa que você não pode usar isso como um armazenamento de events, mas pode ser melhor usar outra coisa. Dê uma olhada na EventStore para uma alternativa.

ATUALIZAR

Documentação Kafka :

A terceirização de evento é um estilo de design de aplicativo no qual as alterações de estado são registradas como uma seqüência de registros ordenada por tempo. O suporte de Kafka a dados de log armazenados muito grandes o torna um excelente back-end para um aplicativo construído nesse estilo.

ATUALIZAÇÃO 2

Uma preocupação em usar o Kafka para o sourcing de events é o número de tópicos necessários. Normalmente, no fornecimento de events, há um stream (tópico) de events por entidade (como usuário, produto, etc). Dessa forma, o estado atual de uma entidade pode ser reconstituído, reaplicando todos os events no stream. Cada tópico do Kafka consiste em uma ou mais partições e cada partição é armazenada como um diretório no sistema de arquivos. Também haverá pressão do ZooKeeper à medida que o número de znodes aumentar.

Eu sou um dos autores originais de Kafka. Kafka funcionará muito bem como um log para o sourcing de events. É tolerante a falhas, dimensiona-se para enormes tamanhos de dados e possui um modelo de particionamento integrado.

Nós o usamos para vários casos de uso deste formulário no LinkedIn. Por exemplo, nosso sistema de processamento de stream de código aberto, o Apache Samza, vem com suporte integrado para o fornecimento de events.

Eu acho que você não ouve muito sobre o uso de Kafka para o sourcing de events, principalmente porque a terminologia de terceirização de events não parece ser muito prevalente no espaço web do consumidor, onde o Kafka é mais popular.

Eu escrevi um pouco sobre esse estilo de uso de Kafka aqui .

Você pode usar o Kafka como armazenamento de events, mas eu não recomendo fazê-lo, embora possa parecer uma boa escolha:

  • O Kafka só garante pelo menos uma vez o fornecimento e há duplicatas no armazenamento de events que não podem ser removidas. Atualização: Aqui você pode ler porque é tão difícil com Kafka e algumas últimas notícias sobre como finalmente atingir esse comportamento: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how -apache-kafka-does-it /
  • Devido à imutabilidade, não há como manipular o armazenamento de events quando a aplicação evolui e os events precisam ser transformados (obviamente, existem methods como upcasting, mas …). Pode-se dizer que você nunca precisa transformar events, mas isso não é uma suposição correta, pode haver uma situação em que você faz backup do original, mas atualiza-os para as versões mais recentes. Esse é um requisito válido em arquiteturas orientadas a events.
  • Não há lugar para persistir snapshots de entidades / agregações e o replay se tornará mais lento e lento. Criar instantâneos é necessário para o armazenamento de events a partir da perspectiva de longo prazo.
  • As partições do Kafka são distribuídas e são difíceis de gerenciar e fazer backup de comparação com bancos de dados. Bancos de dados são simplesmente mais simples 🙂

Então, antes de fazer sua escolha, você pensa duas vezes. Armazenamento de events como combinação de interfaces da camada de aplicação (monitoramento e gerenciamento), armazenamento SQL / NoSQL e Kafka como broker é melhor escolha do que deixar o Kafka lidar com ambas as funções para criar uma solução completa de resources completos.

A loja de events é um serviço complexo que requer mais do que o Kafka pode oferecer se você for sério na aplicação de terceirização de events, CQRS, Sagas e outros padrões na arquitetura orientada a events e manter o alto desempenho.

Sinta-se livre para desafiar minha resposta! Você pode não gostar do que eu digo sobre o seu corretor favorito com muita sobreposição de resources, mas ainda assim, o Kafka não foi projetado como armazenamento de events, mas mais como corretor de alto desempenho e buffer ao mesmo tempo para lidar com produtores rápidos versus cenários de consumidores lentos. por exemplo.

Por favor, olhe a estrutura open source eventuate.io microservices para descobrir mais sobre os possíveis problemas: http://eventuate.io/

Atualização a partir de 8 de fevereiro de 2018

Eu não incorporo novas informações de comentários, mas concordo com alguns desses aspectos. Esta atualização é mais sobre algumas recomendações para plataforma orientada a events de microsserviço. Se você é sério sobre o design robusto do microsserviço e o desempenho mais alto possível em geral, eu lhe darei algumas dicas de que você pode estar interessado.

  1. Não use Spring – é ótimo (eu uso muito), mas é pesado e lento ao mesmo tempo. E não é uma plataforma de microsserviço. É “apenas” um framework para ajudar você a implementar um (muito trabalho por trás disso …). Outras estruturas são “apenas” leves REST ou JPA ou estruturas de foco diferenciado. Eu recomendo provavelmente a melhor plataforma completa de microsserviço de código aberto disponível, que está voltando às raízes do Java puro: https://github.com/networknt

Se você quer saber sobre o desempenho, pode comparar-se com o pacote de benchmark existente. https://github.com/networknt/microservices-framework-benchmark

  1. Não use Kafka em tudo :-)) É meia piada. Quero dizer, enquanto Kafka é ótimo, é outro sistema centrado em corretor. Eu acho que o futuro está em sistemas de mensagens sem broker. Você pode se surpreender, mas há sistemas Kafka mais rápidos do que o Kafka :-), é claro que você deve descer para o nível mais baixo. Olhe para o Chronicle.

  2. Para o armazenamento de Eventos, eu recomendo uma extensão superior do Postgresql chamada TimescaleDB, que se concentra no processamento de dados de timeseries de alto desempenho (events são timeseries) em grande volume. Claro CQRS, Event sourcing (replay, etc resources) são construídos em framework light4j fora da checkbox que usa o Postgres como armazenamento baixo.

  3. Para mensagens, tente olhar para Chronicle Queue, Map, Engine, Network. Quero dizer, livre-se dessas soluções cinputs em corretores antiquados e use o sistema de micro-mensagens (incorporado). Chronicle Queue é na verdade ainda mais rápido que Kafka. Mas eu concordo que não é tudo em uma solução e você precisa fazer algum desenvolvimento caso contrário você vai e compra a versão Enterprise (paga um). No final, o esforço para construir a partir de Chronicle sua própria camada de mensagens será pago, removendo o fardo de manter o cluster de Kafka.

Eu continuo voltando para este QA. E eu não achei as respostas existentes com nuances suficientes, então estou adicionando essa resposta.

TL; DR. Sim ou Não, dependendo do uso de terceirização do evento.

Existem dois tipos principais de sistemas de origem de events, dos quais estou ciente.

Processadores de events a jusante = Sim

Nesse tipo de sistema, os events acontecem no mundo real e são registrados como fatos. Tal como um sistema de armazém para acompanhar paletes de produtos. Basicamente não há events conflitantes. Tudo já aconteceu, mesmo que estivesse errado. (Ou seja, palete 123456 colocar no caminhão A, mas foi agendada para o caminhão B.) Em seguida, os fatos são verificados para exceções através de mecanismos de informação. O Kafka parece bem adequado para esse tipo de aplicativo de processamento de events a jusante.

Nesse contexto, é compreensível que o pessoal do Kafka esteja defendendo isso como uma solução de terceirização de events. Por ser bastante semelhante a como ele já é usado, por exemplo, clique em streams. No entanto, as pessoas que usam o termo Event Sourcing (em oposição ao Stream Processing) provavelmente estão se referindo ao segundo uso …

Fonte de verdade controlada por aplicativo = não

Esse tipo de aplicativo declara seus próprios events como resultado de solicitações do usuário que passam pela lógica de negócios. Kafka não funciona bem neste caso por dois motivos principais.

Falta de isolamento da entidade

Este cenário precisa da capacidade de carregar o stream de events para uma entidade específica. O motivo comum para isso é construir um modelo de gravação transiente para a lógica de negócios usar para processar a solicitação. Fazer isso é impraticável em Kafka. O uso de tópico por entidade poderia permitir isso, exceto que esse não é um bom começo quando pode haver milhares ou milhões dessa entidade. Isto deve-se aos limites técnicos no Kafka / Zookeeper. O uso de topic-per-type é recomendado para o Kafka, mas isso exigiria o carregamento de events para cada entidade desse tipo apenas para obter events para uma única entidade. Desde que você não pode dizer por posição de log quais events pertencem a qual entidade. Mesmo usando Snapshots para iniciar a partir de uma posição de log conhecida, esse pode ser um número significativo de events para serem transmitidos. Mas instantâneos não podem ajudá-lo com alterações de código. Porque a adição de novos resources à lógica de negócios pode tornar os instantâneos anteriores estruturalmente incompatíveis. Portanto, ainda é necessário fazer uma reprodução de tópico nesses casos para construir um novo modelo. Uma das principais razões para usar um modelo de gravação transiente em vez de persistente é tornar a lógica de negócios mais barata e fácil de implantar.

Falta de detecção de conflito

Em segundo lugar, os usuários podem criar condições de corrida devido a solicitações simultâneas contra a mesma entidade. Pode ser bastante indesejável salvar events conflitantes e resolvê-los após o fato. Por isso, é importante poder evitar events conflitantes. Para dimensionar o carregamento de solicitações, é comum usar serviços sem estado, evitando conflitos de gravação usando gravações condicionais (escreva somente se o último evento de entidade for #x). concurrency Otimista da Aka. Kafka não suporta simultaneidade otimista. Mesmo que o apoiasse no nível do tópico, precisaria estar todo no caminho até o nível da entidade para ser eficaz. Para usar o Kafka e evitar events conflitantes, você precisaria usar um gravador serializado com estado no nível do aplicativo. Esse é um requisito / restrição de arquitetura significativa.

Outras informações


Atualizar por comentário

Isso era muito grande para caber em um comentário. Parece que a maioria das pessoas implementa sua própria implementação de armazenamento de events sobre um database existente. Para cenários não distribuídos, como back-ends internos ou produtos independentes, é bem documentado como criar um armazenamento de events baseado em SQL. E há bibliotecas disponíveis sobre bancos de dados de vários tipos. Há também o EventStore, que é construído para esse propósito.

Em cenários distribuídos, vi algumas implementações diferentes. O projeto do Jet Panther usa o Azure CosmosDB , com o recurso Alterar feed para notificar os ouvintes. Outra implementação semelhante da AWS que eu já ouvi sobre isso é usar o DynamoDB com seu recurso Streams para notificar os ouvintes. A chave de partição provavelmente deve ser o ID do stream para melhor distribuição de dados (para diminuir o excesso de provisionamento). No entanto, um replay completo em streams no Dynamo é caro (lido e custo-sábio). Então, este impl também foi configurado para que o Dynamo Streams despeje events no S3. Quando um novo ouvinte fica on-line ou um ouvinte existente deseja uma reprodução completa, ele lê o S3 para recuperar o atraso primeiro.

Meu projeto atual é um cenário multi-tenant, e eu rolei meu próprio no topo do Postgres. Algo como o Citus parece apropriado para escalabilidade, particionamento por tentant + stream.

Kafka ainda é muito útil em cenários distribuídos. É um problema não trivial expor os events de cada serviço a outros serviços. Um armazenamento de events não é construído para isso normalmente, mas é precisamente isso que o Kafka faz bem. Cada serviço tem sua própria fonte interna de verdade (pode ser armazenamento de events ou de outra forma), mas ouve Kafka saber o que está acontecendo “fora”. A equipe também pode publicar seus events de serviço em Kafka para informar o “fora” de coisas interessantes que o serviço fez.

Sim, você pode usar o Kafka como uma loja de events. Ele funciona muito bem, especialmente com a introdução do Kafka Streams , que fornece uma maneira nativa do Kafka de processar seus events no estado acumulado que você pode consultar .

A respeito de:

Capacidade de reproduzir o log de events que permite a capacidade de novos assinantes se registrarem no sistema após o fato.

Isso pode ser complicado. Cobri isso em detalhes aqui: https://stackoverflow.com/a/48482974/741970