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

219

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

Um dos principais pontos que Kafka suporta:

  • Captura / armazenamento de eventos, todos os HA, é claro.
  • Arquitetura de pub / sub
  • Capacidade de reproduzir o log de eventos, o que permite que novos assinantes se registrem no sistema após o fato.

É certo que eu não sou 100% versado em CQRS / Event sourcing, mas isso parece bem próximo do que um eventstore deveria ser. O engraçado é que eu realmente não consigo descobrir muito sobre Kafka sendo usado como loja de eventos, então talvez eu esteja perdendo alguma coisa.

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

Basicamente, o estado do sistema é salvo com base nas transações / eventos que o sistema já recebeu, em vez de apenas salvar o estado / instantâneo atual do sistema, o que geralmente é feito. (Pense nisso como um razão geral em contabilidade: todas as transações acabam chegando ao estado final). Isso permite todo tipo de coisas legais, mas basta ler os links fornecidos.

Geert-Jan
fonte
Olá Geert-Jan. Em retrospectiva, como você lidou com esse problema? Eu tenho uma pergunta relacionada (exposta aqui: stackoverflow.com/questions/58763727/… ). A maioria das pessoas que sugere a adoção de Kafka parece confiar nos pontos de inututibilidade do log de acréscimo, alto rendimento e garantia de ordem de partição. (100% de garantia ordem implica utilizando apenas uma partição -killing simultaneidade)
Tony _008
Não persegui no final porque terminei esse projeto paralelo. Portanto, não tenho uma resposta clara, estou com medo.
Geert-Jan

Respostas:

119

O Kafka deve ser um sistema de mensagens com muitas semelhanças com um armazenamento de eventos, mas para citar sua introdução:

O cluster Kafka mantém todas as mensagens publicadas - tenham sido consumidas ou não - por um período configurável . Por exemplo, se a retenção for definida por dois dias, os dois dias após a publicação de uma mensagem estarão disponíveis para consumo, após o que serão descartados para liberar espaço. O desempenho do Kafka é efetivamente constante em relação ao tamanho dos dados, portanto, reter muitos dados não é um problema.

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

ATUALIZAR

Documentação Kafka :

A origem de eventos é um estilo de design de aplicativo em que as alterações de estado são registradas como uma sequência de registros ordenada por tempo. O suporte do Kafka a dados de log armazenados muito grandes o torna um excelente back-end para um aplicativo criado nesse estilo.

ATUALIZAÇÃO 2

Uma preocupação com o uso do Kafka para fornecimento de eventos é o número de tópicos necessários. Normalmente, na fonte de eventos, há um fluxo (tópico) de eventos por entidade (como usuário, produto etc.). Dessa forma, o estado atual de uma entidade pode ser reconstituído reaplicando todos os eventos no fluxo. 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 aumenta.

eulerfx
fonte
16
Eu estava olhando para Kafka e tinha outra preocupação: não notei nada sobre simultaneidade otimista. Idealmente, eu poderia dizer: "Adicione este evento como item N + 1 somente se o evento mais recente do objeto ainda for N."
Darien
2
@ Darien: Provavelmente vou com uma configuração em que o Redis alimenta o Kafka (usando o Redis Notifications ). Desde Redis permite a simultaneidade otimista (usando Assistir / multi-exec), isso deve funcionar
Geert-Jan
2
@ Darien Não sou especialista em terceirização de eventos, mas meu entendimento é que, de um modo geral, você não precisaria de concorrência otimista porque os eventos são, por definição, registros de coisas que já aconteceram historicamente.
John
4
@ John, eu acho que se você já tem uma ordem autorizada de eventos não conflitantes, isso implica que onde quer que eles morem seja a sua tecnologia atual de armazenamento de eventos, e o Kafka está apenas sendo usado como um sistema secundário para distribuí-los.
Darien
1
Também há informações valiosas aqui: groups.google.com/forum/#!topic/dddcqrs/rm02iCfffUY
manuc66
283

Eu sou um dos autores originais de Kafka. O Kafka funcionará muito bem como um registro para o fornecimento de eventos. É tolerante a falhas, dimensiona para enormes tamanhos de dados e possui um modelo de particionamento embutido.

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

Acho que você não ouve muito sobre o uso do Kafka para fornecimento de eventos, principalmente porque a terminologia do fornecimento de eventos não parece ser muito prevalente no espaço da Web do consumidor em que o Kafka é mais popular.

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

Jay Kreps
fonte
2
Ia postar esse link :) Impressionante post no blog. Teria sido bom poder comentar, porque tenho muitas perguntas. @ Geert-Jan também dar uma olhada em "arquitetura Lambda", este é bastante semelhante e o nome é dado pela tempestade autor, principalmente usando algum tipo de log de eventos Hadoop baseado em muitos exemples
Sebastien Lorber
6
@ Jay: Desde que eu renovei o interesse neste tópico, você poderia, por favor, detalhar um pouco o fato de que Kafka parece ter sido projetado para que suas mensagens publicadas expirem após um determinado período de tempo? Se você usar o Kafka como fonte de eventos, as mensagens deverão ser armazenadas indefinidamente. Provavelmente é configurável, mas isso representaria um problema?
Geert-Jan
2
Existe alguma comparação entre kafka e eventstore? Gosto especificamente do foco no FRP no eventstore chamado Projections. Existe algo assim em Kafka / Samza?
CMCDragonkai
4
Também estou interessado na pergunta de @ Geert-Jan para Jay. O Kafka não é adequado para o lado transacional da fonte de eventos real, devido à necessidade de um fluxo de eventos (tópico) por agregado de domínio (pense em milhões). No entanto, é ideal para receber eventos de, por exemplo, GetEventStore. Mas isso funcionará apenas com eventos infinitamente retidos (no nosso caso) e, além de alguns breves comentários, esse parece não ser um caso de uso suportado pelo Kafka? Estou enganado aqui? O Samza, por exemplo, assume que existem apenas dois cenários: retenção baseada em tempo ou retenção baseada em chave. Existem outros ..
Stephen Drew
3
@eulerfx Supondo que gostaríamos de usar o Kafka como armazenamento para o sistema de origem de eventos, como o bloqueio / simultaneidade otimista deve ser implementado?
Krzysztof Branicki
51

Continuo voltando a este controle de qualidade. E não encontrei as respostas existentes sutis o suficiente, por isso estou adicionando esta.

TL; DR. Sim ou Não, dependendo do uso da fonte de eventos.

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

Processadores de eventos a jusante = Sim

Nesse tipo de sistema, os eventos acontecem no mundo real e são registrados como fatos. Como um sistema de armazém para acompanhar paletes de produtos. Basicamente, não há eventos conflitantes. Tudo já aconteceu, mesmo que estivesse errado. (Ou seja, o palete 123456 foi colocado no caminhão A, mas foi programado para o caminhão B.) Posteriormente, os fatos são verificados quanto a exceções por meio de mecanismos de relatório. Kafka parece bem adequado para esse tipo de aplicativo de processamento de eventos downstream.

Nesse contexto, é compreensível o motivo pelo qual a Kafka a defende como uma solução de Event Sourcing. Porque é bem parecido com o modo como já é usado, por exemplo, fluxos de cliques. 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 eventos como resultado de solicitações de usuários passando pela lógica de negócios. Kafka não funciona bem nesse caso por dois motivos principais.

Falta de isolamento da entidade

Esse cenário precisa da capacidade de carregar o fluxo de eventos para uma entidade específica. O motivo comum para isso é criar um modelo de gravação transitório 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 pode permitir isso, exceto que não é um iniciador quando pode haver milhares ou milhões de entidades. Isso ocorre devido aos limites técnicos no Kafka / Zookeeper.

Um dos principais motivos para usar um modelo de gravação transitório dessa maneira é tornar as alterações da lógica de negócios baratas e fáceis de implantar.

Em vez disso, é recomendável usar o tópico por tipo para o Kafka, mas isso exigiria o carregamento de eventos para cada entidade desse tipo apenas para obter eventos para uma única entidade. Como você não pode dizer por posição de log quais eventos 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 eventos para agitar.

Falta de detecção de conflitos

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 eventos conflitantes e resolvê-los após o fato. Portanto, é importante ser capaz de evitar eventos conflitantes. Para dimensionar o carregamento de solicitações, é comum usar serviços sem estado, enquanto evita conflitos de gravação usando gravações condicionais (somente gravações se o último evento da entidade for #x). Simulação simultânea otimista. Kafka não suporta simultaneidade otimista. Mesmo que o apoiasse no nível do tópico, seria necessário ir até o nível da entidade para ser eficaz. Para usar o Kafka e evitar eventos conflitantes, você precisará usar um gravador com estado e serializado no nível do aplicativo. Este é um requisito / restrição arquitetural significativo.

Outras informações


Atualizar por comentário

O comentário foi excluído, mas a pergunta era algo como: o que as pessoas usam para armazenamento de eventos?

Parece que a maioria das pessoas lança sua própria implementação de armazenamento de eventos em um banco de dados existente. Para cenários não distribuídos, como back-ends internos ou produtos independentes, está bem documentado como criar um armazenamento de eventos baseado em SQL. E existem bibliotecas disponíveis no banco de dados de vários tipos. Também existe o EventStore , criado para esse fim.

Em cenários distribuídos, vi algumas implementações diferentes. O projeto Panther do Jet usa o Azure CosmosDB , com o recurso Alterar Feed para notificar os ouvintes. Outra implementação semelhante que ouvi na AWS está usando o DynamoDB com seu recurso Streams para notificar os ouvintes. A chave da partição provavelmente deve ser a identificação do fluxo para melhor distribuição de dados (para diminuir a quantidade de provisionamento em excesso). No entanto, uma repetição completa entre fluxos no Dynamo é cara (leitura e custo). Portanto, esse impl também foi configurado para o Dynamo Streams despejar eventos no S3. Quando um novo ouvinte fica online, ou um ouvinte existente deseja uma repetição completa, ele lê o S3 para recuperar o atraso.

Meu projeto atual é um cenário de vários inquilinos, e eu montei o meu em cima do Postgres. Algo como o Citus parece apropriado para escalabilidade, particionando por tentativa + fluxo.

Kafka ainda é muito útil em cenários distribuídos. É um problema não trivial expor os eventos de cada serviço a outros serviços. Uma loja de eventos não é construída para isso normalmente, mas é exatamente isso que Kafka faz bem. Cada serviço tem sua própria fonte interna de verdade (pode ser o armazenamento de eventos ou não), mas ouve Kafka para saber o que está acontecendo "fora". O serviço também pode postar eventos em Kafka para informar o "exterior" de coisas interessantes que o serviço fez.

Kasey Speakman
fonte
1
@Dominik Mencionei o EventStore na seção Atualização (segundo parágrafo). Vou voltar e ligá-lo. Eu tentei, e tem um desempenho impressionante. Para nossa pequena equipe, a não introdução de outro banco de dados foi considerada mais importante no momento, daí o Postgres (que também é usado para visualizações). É possível que mudemos para a EventStore no futuro ou em produtos futuros.
Kasey Speakman
2
Os tópicos do @KaseySpeakman não são iguais às partições. Um tópico possui uma ou mais partições. É garantido que as partições têm apenas um consumidor por grupo em um determinado momento. Particione suas entidades de forma a tirar proveito disso. Você não precisa de um tópico por entidade ou mesmo de uma partição por entidade. Você só precisa particioná-los de forma a garantir que todos os comandos endereçados à mesma entidade vão para a mesma partição.
Andrew Larsson
1
@KaseySpeakman Muitas entidades podem compartilhar uma única partição. Quem disse que você sempre precisa carregar o estado da entidade diretamente do armazenamento de eventos, reproduzindo os eventos? Existem outras maneiras de alcançar o mesmo conceito sem seguir rigorosamente a implementação de Greg Young, linha por linha.
Andrew Larsson
1
@AndrewLarsson Se você não particionar por entidade, como evitar eventos conflitantes no nível da entidade? Como voltamos ao círculo completo dos conflitos de simultaneidade, talvez você deva postar seu próprio artigo em mídias ou algo sobre como você usou o Kafka para fornecimento de eventos (não processamento de fluxo) na produção. Como você o realiza com partição por tipo e sem controle de simultaneidade no nível da entidade. Eu o leria e nem sequer o vasculharia nos comentários se discordasse.
Kasey Speakman
2
@KaseySpeakman Usar o Kafka dessa maneira não é nada fácil. Mas se você está na escala em que considerou seriamente o CQRS e o Event Sourcing, está na escala em que não pode se dar ao luxo de fazer as coisas da maneira mais fácil. Seu modelo de concorrência afeta diretamente sua escala - não escolha um arbitrariamente. Além disso, o HTTP não é um transporte confiável e, novamente, se você estiver nessa escala, não poderá gastar tempo resolvendo problemas de mensagens perdidas e / ou duplicadas. Tudo isso pode ser resolvido usando o Kafka entre o cliente e o processador de comandos, mas sim, isso tem um custo de complexidade.
Andrew Larsson
20

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

  • O Kafka garante apenas pelo menos uma vez a entrega e há duplicatas no armazenamento de eventos que não podem ser removidas. Atualização: Aqui você pode ler por que é tão difícil com Kafka e algumas notícias mais recentes sobre como finalmente conseguir esse comportamento: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how -apache-kafka-it-it /
  • Devido à imutabilidade, não há como manipular o armazenamento de eventos quando o aplicativo evolui e os eventos precisam ser transformados (é claro que existem métodos como upcasting, mas ...). Pode-se dizer que você nunca precisa transformar eventos, mas isso não é uma suposição correta, pode haver uma situação em que você faz o backup do original, mas os atualiza para as versões mais recentes. Esse é um requisito válido em arquiteturas orientadas a eventos.
  • Nenhum lugar para persistir instantâneos de entidades / agregados e repetições se tornará cada vez mais lento. A criação de capturas instantâneas é um recurso obrigatório para armazenamento de eventos da perspectiva de longo prazo.
  • Dado que as partições Kafka são distribuídas e são difíceis de gerenciar e comparar com os bancos de dados. Bancos de dados são simplesmente mais simples :-)

Então, antes de fazer sua escolha, você pensa duas vezes. O armazenamento de eventos como combinação de interfaces da camada de aplicação (monitoramento e gerenciamento), o armazenamento SQL / NoSQL e o Kafka como intermediário é a melhor opção do que deixar o Kafka lidar com ambas as funções para criar uma solução completa com todos os recursos.

O armazenamento de eventos é um serviço complexo que requer mais do que o Kafka pode oferecer se você for sério sobre a aplicação de sourcing de eventos, CQRS, Sagas e outros padrões na arquitetura orientada a eventos e permanecer com alto desempenho.

Sinta-se livre para desafiar minha resposta! Talvez você não goste do que eu digo sobre seu corretor favorito com muitos recursos sobrepostos, mas ainda assim, o Kafka não foi projetado como armazenamento de eventos, mas mais como corretor e buffer de alto desempenho ao mesmo tempo para lidar com produtores rápidos e cenários lentos de consumidores, por exemplo.

Consulte a estrutura de código-fonte aberto event microservices para descobrir mais sobre os possíveis problemas: http://eventuate.io/

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

Não incorporo novas informações nos comentários, mas concordo com alguns desses aspectos. Esta atualização é mais sobre algumas recomendações para a plataforma orientada a eventos de microsserviço. Se você é sério sobre o design robusto dos microsserviços e o desempenho mais alto possível em geral, fornecerei algumas dicas que podem lhe interessar.

  1. Não use o Spring - é ótimo (eu mesmo uso muito), mas é pesado e lento ao mesmo tempo. E não é uma plataforma de microsserviço. É "apenas" uma estrutura para ajudá-lo a implementar um (muito trabalho por trás disso ..). Outras estruturas são "apenas" REST ou JPA leve ou estruturas com foco diferente. Recomendo que provavelmente seja a melhor plataforma completa de microsserviço de código aberto disponível no mercado, que está voltando às raízes Java puras: https://github.com/networknt

Se você se pergunta sobre desempenho, pode comparar-se ao conjunto de benchmarks existente. https://github.com/networknt/microservices-framework-benchmark

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

  2. Para o armazenamento de eventos, recomendo a extensão superior do Postgresql chamada TimescaleDB, que se concentra no processamento de dados de séries temporais de alto desempenho (eventos são séries temporais) em grande volume. É claro que o CQRS, recursos de fonte de eventos (repetição, etc.) são construídos no framework light4j, prontos para usar, que usa o Postgres como pouco armazenamento.

  3. Para mensagens, tente olhar para Chronicle Queue, Map, Engine, Network. Quero dizer, livrar-se dessas soluções centradas em corretores à moda antiga e usar o sistema de micro messaging (incorporado). A fila de crônicas é realmente ainda mais rápida que Kafka. Mas eu concordo que não é tudo em uma solução e você precisa fazer algum desenvolvimento, caso contrário você compra a versão Enterprise (paga uma). No final, o esforço para construir a partir do Chronicle sua própria camada de mensagens será pago, removendo o ônus de manter o cluster Kafka.

kensai
fonte
Vista interessante. Gostaria de elaborar alguns pontos? > Kafka apenas garante pelo menos uma vez a entrega e há duplicatas no armazenamento de eventos que não podem ser removidas. Você parece sugerir que existe uma entrega exatamente uma vez. afaik (e tenho certeza disso) não existe tal coisa em um sistema distribuído. 2) Quanto ao seu ponto 2: a escola clássica de (fonte de eventos / dddd) pensa que os eventos são inerentemente imutáveis. Ou seja: eles aconteceram, não há como mudar o passado. Qual é a utilidade real de alterá-los em retrospecto? Obrigado!
Geert-Jan
1.) Hazelcast para garantir que cada mensagem será processada uma vez e apenas uma vez. 2.) Não gosto de nada como _V2 no código de serviço; portanto, você fará backup para arquivar e recriar eventos antigos para suas novas versões (você ainda tem a verdade original) ou poderá ocultar / criar essa funcionalidade diretamente no Event Armazene a funcionalidade de captura instantânea, para que haja um ponto único de upcasting -> o armazenamento de eventos. Quais são as suas soluções para isso?
kensai
1) pelo menos uma vez + idempotência no consumidor. Ou seja: verifique se o evento já foi visto. Se sim, pule. Ou, melhor ainda, tenha ações idempotentes. Obviamente, isso nem sempre é possível. 2) Eu nunca encontrei a necessidade de versão eventos. Eu sempre trato os eventos em si como a fonte da verdade e incluo todas as informações que eu precisaria sobre eles. Fazendo isso, nunca encontrei uma situação em que precisava de uma estrutura de eventos diferente e / ou dados sobre um evento. Mas talvez sim. Interessado em ouvir em quais situações você realmente precisaria ter eventos atualizados.
Geert-Jan
1.) pode ser uma opção. 2.) então suas estruturas de dados eram perfeitas desde o início :-) sorte sua, haha. Talvez eu não precise dele no meu projeto atual, mas estou construindo uma plataforma inteira com garfos de eventuate.io mesclado com algumas abordagens JEE de alto desempenho, retiradas apenas do evento de luz 4j ... toda essa discussão não serve para comentários sobre o stackoverflow , mas se você estiver interessado em mergulhar mais fundo eu recomendo este artigo: leanpub.com/esversioning/read
kensai
1
Kafka suporta exatamente uma vez a entrega agora, a propósito. Update bullet 1
OneCricketeer 2/17/17
8

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

A respeito de:

Capacidade de reproduzir o log de eventos, o que permite que novos assinantes se registrem no sistema após o fato.

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

Dmitry Minkovsky
fonte
0

Sim, o Kafka funciona bem no modelo de fornecimento de eventos, especialmente o CQRS; no entanto, você deve tomar cuidado ao definir TTLs para tópicos e sempre lembre-se de que o Kafka não foi projetado para este modelo, mas podemos usá-lo muito bem.

Brijendra Verma
fonte
0

Eu acho que você deve olhar para o quadro axônio, juntamente com o apoio a Kafka

Darshu Bc
fonte