Utilizzo di Kafka come un Eventstore (CQRS). Buona idea?


219

Anche se mi sono imbattuto in Kafka prima, mi sono appena reso conto che Kafka potrebbe forse essere usato come (la base di) un CQRS , negozio di eventi .

Uno dei punti principali che Kafka supporta:

  • Cattura / memorizzazione di eventi, ovviamente tutti gli HA.
  • Pub / architettura secondaria
  • Possibilità di riprodurre il registro eventi che consente ai nuovi abbonati di registrarsi al sistema dopo il fatto.

Devo ammettere che non sono esperto del CQRS / sourcing di eventi, ma questo sembra abbastanza vicino a quello che dovrebbe essere un negozio di eventi. La cosa divertente è: non riesco davvero a trovare molto sul fatto che Kafka sia usato come un negozio di eventi, quindi forse mi manca qualcosa.

Quindi, qualcosa che manca a Kafka perché sia ​​un buon negozio di eventi? Funzionerebbe? Usandolo produzione? Interessato a approfondimenti, collegamenti, ecc.

Fondamentalmente lo stato del sistema viene salvato in base alle transazioni / eventi che il sistema ha mai ricevuto, invece di salvare semplicemente lo stato / istantanea corrente del sistema che è ciò che viene normalmente fatto. (Consideralo come un libro mastro in contabilità: tutte le transazioni alla fine si sommano allo stato finale) Ciò consente tutti i tipi di cose interessanti, ma basta leggere sui collegamenti forniti.


Ciao Geert-Jan. In retrospettiva, come hai affrontato questo problema? Ho una domanda correlata (esposta qui: stackoverflow.com/questions/58763727/… ). La maggior parte delle persone che suggeriscono l'adozione di Kafka sembrano basarsi sui punti di immutabilità di append-log, throughput elevato e garanzia dell'ordine di partizione. Vedo problemi relativi a ricerche rapide all'interno di argomenti (per la "ricostruzione" dell'entità), Nessuna atomicità transazionale e nessun ordine in tutte le partizioni (La garanzia dell'ordine del 100% implica l'utilizzo di 1 sola partizione - concorrenza di uccisione)
tony _008

Alla fine non l'ho perseverato perché ho terminato quel progetto laterale. Quindi nessuna risposta chiara temo
Geert-Jan

Risposte:


119

Kafka è pensato per essere un sistema di messaggistica che ha molte somiglianze con un negozio di eventi per citare la loro introduzione:

Il cluster Kafka conserva tutti i messaggi pubblicati, indipendentemente dal fatto che siano stati consumati o meno, per un periodo di tempo configurabile . Ad esempio, se la conservazione è impostata per due giorni, per i due giorni successivi alla pubblicazione di un messaggio è disponibile per il consumo, dopodiché verrà scartato per liberare spazio. Le prestazioni di Kafka sono effettivamente costanti rispetto alle dimensioni dei dati, quindi conservare molti dati non è un problema.

Pertanto, mentre i messaggi possono potenzialmente essere conservati indefinitamente, l'aspettativa è che vengano eliminati. Questo non significa che non puoi usarlo come negozio di eventi, ma potrebbe essere meglio usare qualcos'altro. Dai un'occhiata a EventStore per un'alternativa.

AGGIORNARE

Documentazione Kafka :

Il sourcing degli eventi è uno stile di progettazione dell'applicazione in cui le modifiche di stato vengono registrate come una sequenza di record ordinata per tempo. Il supporto di Kafka per dati di registro archiviati molto grandi lo rende un eccellente backend per un'applicazione costruita in questo stile.

AGGIORNAMENTO 2

Una preoccupazione relativa all'utilizzo di Kafka per l'approvvigionamento di eventi è il numero di argomenti richiesti. In genere nel sourcing di eventi, esiste un flusso (argomento) di eventi per entità (come utente, prodotto, ecc.). In questo modo, lo stato corrente di un'entità può essere ricostituito riapplicando tutti gli eventi nel flusso. Ogni argomento di Kafka è costituito da una o più partizioni e ogni partizione è memorizzata come directory sul file system. Ci sarà anche una pressione da parte di ZooKeeper all'aumentare del numero di znodi.


16
Stavo guardando Kafka e avevo un'altra preoccupazione: non avevo notato nulla sulla concorrenza ottimistica. Idealmente potrei dire: "Aggiungi questo evento come elemento N + 1 solo se l'evento più recente dell'oggetto è ancora N."
Darien,

2
@Darien: probabilmente vado con una configurazione in cui Redis alimenta Kafka (usando le notifiche Redis ). Poiché Redis consente una concorrenza ottimistica (usando Watch / multi-exec), questo dovrebbe funzionare
Geert-Jan

2
@Darien Non sono un esperto di approvvigionamento di eventi, ma la mia comprensione era che in generale non avresti bisogno di una concorrenza ottimistica perché gli eventi sono per definizione record di cose che sono già avvenute storicamente.
Giovanni,

4
@John Penso che se hai già un ordinamento autorevole di eventi non in conflitto, ciò implica che ovunque vivano è la tua vera tecnologia di archivio eventi, e Kafka viene appena utilizzato come sistema secondario per distribuirli.
Darien,

1
Ci sono anche informazioni preziose qui: groups.google.com/forum/#!topic/dddcqrs/rm02iCfffUY
manuc66

283

Sono uno degli autori originali di Kafka. Kafka funzionerà molto bene come registro per l'approvvigionamento di eventi. È tollerante ai guasti, si adatta a enormi dimensioni di dati e ha un modello di partizionamento incorporato.

Lo utilizziamo per diversi casi d'uso di questo modulo su LinkedIn. Ad esempio, il nostro sistema di elaborazione di flussi open source, Apache Samza, viene fornito con supporto integrato per l'approvvigionamento di eventi.

Penso che non si senta molto sull'utilizzo di Kafka per l'approvvigionamento di eventi principalmente perché la terminologia di approvvigionamento degli eventi non sembra essere molto diffusa nello spazio web dei consumatori in cui Kafka è più popolare.

Ho scritto un po 'su questo stile di utilizzo di Kafka qui .


2
Stavo per pubblicare quel link :) Fantastico post sul blog. Sarebbe stato bello poterlo commentare perché ho molte domande. @ Geert-Jan anche dare un'occhiata a "Lambda architecture", questo è abbastanza simile e il nome è dato dall'autore Storm, principalmente usando una specie di registro degli eventi basato su hadoop in molti esempi
Sebastien Lorber

6
@Jay: Dal momento che ho rinnovato l'interesse per questo argomento, potresti per favore approfondire un po 'il fatto che Kafka sembra progettato per far scadere i suoi messaggi pubblicati dopo un determinato periodo di tempo? Se si utilizza Kafka come fonte di eventi, i messaggi devono essere archiviati indefinitamente. Probabilmente è configurabile, ma ciò costituirebbe un problema?
Geert-Jan,

2
C'è qualche confronto tra kafka ed eventstore? In particolare mi piace il focus su FRP nell'archivio eventi chiamato Proiezioni. C'è qualcosa del genere in Kafka / Samza?
CMCDragonkai,

4
Sono anche interessato alla domanda di @ Geert-Jan a Jay. Kafka non è adatto per il lato transazionale di approvvigionamento di eventi, a causa della necessità di un flusso di eventi (argomento) per aggregato di domini (si pensi a milioni). Tuttavia, è ideale per ricevere eventi da esso, ad esempio GetEventStore. Ma questo funzionerà solo con eventi infinitamente conservati (nel nostro caso) e, a parte alcuni brevi commenti, questo non sembra essere un caso d'uso supportato di Kafka? Mi sbaglio qui? Samza, ad esempio, presuppone che vi siano solo due scenari: conservazione basata sul tempo o conservazione basata su chiave. Ce ne sono altri ..
Stephen Drew,

3
@eulerfx Supponendo che vorremmo usare Kafka come sistema di archiviazione per il sistema di provenienza di eventi come dovrebbe essere implementato il blocco / concorrenza ottimistici?
Krzysztof Branicki,

51

Continuo a tornare a questo QA. E non ho trovato abbastanza sfumate le risposte esistenti, quindi sto aggiungendo questa.

TL; DR. Sì o No, a seconda dell'utilizzo dell'approvvigionamento di eventi.

Esistono due tipi principali di sistemi di origine evento di cui sono a conoscenza.

Processori di eventi a valle = Sì

In questo tipo di sistema, gli eventi accadono nel mondo reale e sono registrati come fatti. Come un sistema di magazzino per tenere traccia dei pallet di prodotti. Non ci sono praticamente eventi contrastanti. È già successo tutto, anche se era sbagliato. (Vale a dire il pallet 123456 messo sul camion A, ma era previsto per il camion B.) Successivamente i fatti vengono controllati per le eccezioni tramite meccanismi di segnalazione. Kafka sembra adatto per questo tipo di down-stream, applicazione per l'elaborazione di eventi.

In questo contesto, è comprensibile il motivo per cui la gente di Kafka lo sta proponendo come soluzione di approvvigionamento di eventi. Perché è abbastanza simile a come viene già utilizzato, ad esempio, nei flussi di clic. Tuttavia, le persone che usano il termine Event Sourcing (in contrapposizione a Stream Processing) si riferiscono probabilmente al secondo utilizzo ...

Fonte di verità controllata dall'applicazione = No

Questo tipo di applicazione dichiara i propri eventi a seguito di richieste degli utenti che passano attraverso la logica aziendale. Kafka non funziona bene in questo caso per due motivi principali.

Mancanza di isolamento dell'entità

Questo scenario richiede la possibilità di caricare il flusso di eventi per un'entità specifica. Il motivo comune per questo è costruire un modello di scrittura temporaneo che la logica aziendale deve utilizzare per elaborare la richiesta. Fare questo è poco pratico in Kafka. L'uso dell'argomento per entità potrebbe consentire ciò, tranne per il fatto che si tratta di un non-principiante quando ci possono essere migliaia o milioni di entità. Ciò è dovuto ai limiti tecnici di Kafka / Zookeeper.

Uno dei motivi principali per utilizzare un modello di scrittura temporaneo in questo modo è rendere le modifiche della logica di business economiche e facili da implementare.

L'uso di topic-per-type è raccomandato invece per Kafka, ma ciò richiederebbe il caricamento di eventi per ogni entità di quel tipo solo per ottenere eventi per una singola entità. Poiché non è possibile stabilire in base alla posizione del registro quali eventi appartengono a quale entità. Anche usando le istantanee per iniziare da una posizione di registro nota, questo potrebbe essere un numero significativo di eventi da sfogliare.

Mancanza di rilevamento dei conflitti

In secondo luogo, gli utenti possono creare condizioni di gara a causa di richieste simultanee contro la stessa entità. Potrebbe essere abbastanza indesiderabile salvare eventi in conflitto e risolverli dopo il fatto. Quindi è importante essere in grado di prevenire eventi contrastanti. Per ridimensionare il carico delle richieste, è comune utilizzare i servizi senza stato e prevenire conflitti di scrittura utilizzando le scritture condizionali (scrivere solo se l'ultimo evento dell'entità era #x). Concorrenza ottimistica di Aka. Kafka non supporta la concorrenza ottimistica. Anche se lo supportasse a livello di argomento, dovrebbe essere fino al livello dell'entità per essere efficace. Per utilizzare Kafka e prevenire eventi contrastanti, è necessario utilizzare un writer con stato con serializzazione a livello di applicazione. Si tratta di un requisito / limitazione architettonica significativa.

Ulteriori informazioni


Aggiornamento per commento

Il commento è stato eliminato, ma la domanda era qualcosa del genere: cosa usano le persone per l'archiviazione degli eventi?

Sembra che la maggior parte delle persone esegua l'implementazione dell'archiviazione degli eventi su un database esistente. Per scenari non distribuiti, come back-end interni o prodotti autonomi, è ben documentato come creare un archivio eventi basato su SQL. E ci sono librerie disponibili su database di vario genere. C'è anche EventStore , che è stato progettato per questo scopo.

In scenari distribuiti, ho visto un paio di implementazioni diverse. Il progetto Jet Panther usa Azure CosmosDB , con la funzionalità Feed di modifica per avvisare i listener. Un'altra implementazione simile di cui ho sentito parlare su AWS è l'utilizzo di DynamoDB con la sua funzione Stream per avvisare gli ascoltatori. La chiave di partizione probabilmente dovrebbe essere l'id del flusso per la migliore distribuzione dei dati (per ridurre la quantità di over-provisioning). Tuttavia, un replay completo attraverso gli stream in Dynamo è costoso (letto e dal punto di vista dei costi). Quindi questo impianto è stato anche configurato per Dynamo Streams per scaricare eventi su S3. Quando un nuovo ascoltatore viene online, o un ascoltatore esistente desidera un replay completo, leggerebbe S3 per primo.

Il mio progetto attuale è uno scenario multi-tenant e ho realizzato il mio oltre a Postgres. Qualcosa come Citus sembra appropriato per la scalabilità, partizionamento per tentant + stream.

Kafka è ancora molto utile in scenari distribuiti. È un problema non banale esporre gli eventi di ciascun servizio ad altri servizi. Un negozio di eventi non è stato creato per questo in genere, ma è esattamente ciò che Kafka fa bene. Ogni servizio ha una propria fonte interna di verità (potrebbe essere la memorizzazione di eventi o altro), ma ascolta Kafka per sapere cosa sta succedendo "all'esterno". Il servizio può anche pubblicare eventi a Kafka per informare il "fuori" di cose interessanti che il servizio ha fatto.


1
@Dominik Ho menzionato EventStore nella sezione Aggiornamento (2 ° paragrafo). Tornerò indietro e lo collegherò. L'ho provato e ha una perfezione impressionante. Per il nostro piccolo team, per ora non è stato ritenuto più importante introdurre un altro database, quindi Postgres (che viene utilizzato anche per le visualizzazioni). È possibile che ci spostiamo su EventStore in futuro o in prodotti futuri.
Kasey Speakman,

2
@KaseySpeakman Gli argomenti non sono gli stessi delle partizioni. Un argomento ha una o più partizioni. Le partizioni sono garantite per avere un solo consumatore per gruppo in un dato momento. Suddividere le entità in modo tale da trarne vantaggio. Non è necessario un argomento per entità o anche una partizione per entità. Hai semplicemente bisogno di partizionarli in modo tale da garantire che tutti i comandi indirizzati alla stessa entità passino alla stessa partizione.
Andrew Larsson,

1
@KaseySpeakman Molte entità possono condividere una singola partizione. Chi ha detto che devi sempre caricare lo stato dell'entità direttamente dall'archivio eventi riproducendo gli eventi? Esistono altri modi per raggiungere lo stesso concetto senza seguire rigorosamente l'implementazione di Greg Young.
Andrew Larsson,

1
@AndrewLarsson Se non si partiziona per entità, come si prevengono gli eventi in conflitto a livello di entità? Dato che siamo tornati ai conflitti di concorrenza, allora forse dovresti pubblicare il tuo articolo su supporto o qualcosa di simile su come hai usato Kafka per l'approvvigionamento di eventi (non l'elaborazione in streaming) in produzione. Come lo realizzi con la partizione per tipo e senza controllo di concorrenza a livello di entità. Lo leggerei e non ti trollerei nei commenti se non fossi d'accordo.
Kasey Speakman,

2
@KaseySpeakman Usare Kafka in questo modo non è affatto semplice. Ma se sei nella scala in cui hai preso seriamente in considerazione CQRS ed Event Sourcing, allora sei nella scala in cui non puoi permetterti di fare le cose nel modo più semplice. Il tuo modello di concorrenza ha un impatto diretto sulla tua scala: non sceglierne uno arbitrariamente. Inoltre, HTTP non è un trasporto affidabile e, di nuovo, se sei su quella scala, non puoi permetterti di passare il tempo a risolvere i problemi persi e / o duplicati dei messaggi. Tutto ciò può essere risolto usando Kafka tra il client e il processore dei comandi, ma sì, ha un costo di complessità.
Andrew Larsson,

20

Puoi usare Kafka come negozio di eventi, ma non ti consiglio di farlo, anche se potrebbe sembrare una buona scelta:

  • Kafka garantisce la consegna almeno una volta e ci sono duplicati nell'archivio eventi che non possono essere rimossi. Aggiornamento: qui puoi leggere perché è così difficile con Kafka e alcune ultime notizie su come ottenere finalmente questo comportamento: https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how -apache-Kafka-fa-it /
  • A causa dell'immutabilità, non c'è modo di manipolare l'archivio eventi quando l'applicazione si evolve e gli eventi devono essere trasformati (ci sono ovviamente metodi come l'upgrade, ma ...). Una volta si potrebbe dire che non è mai necessario trasformare gli eventi, ma questo non è un presupposto corretto, potrebbe esserci una situazione in cui si esegue il backup dell'originale, ma si aggiorna alle ultime versioni. Questo è un requisito valido nelle architetture guidate dagli eventi.
  • Nessun luogo in cui persistere istantanee di entità / aggregati e riproduzione diventerà sempre più lento. La creazione di snapshot è indispensabile per l'archivio eventi da una prospettiva a lungo termine.
  • Dato che le partizioni Kafka sono distribuite e sono difficili da gestire e il backup si confronta con i database. I database sono semplicemente più semplici :-)

Quindi, prima di fare la tua scelta, ci pensi due volte. L'archivio eventi come combinazione di interfacce a livello di applicazione (monitoraggio e gestione), archivio SQL / NoSQL e Kafka come broker è la scelta migliore rispetto a lasciare che Kafka gestisca entrambi i ruoli per creare una soluzione completa con funzionalità complete.

Il negozio di eventi è un servizio complesso che richiede molto più di quello che Kafka può offrire se si prende seriamente in considerazione l'applicazione di eventi, CQRS, saghe e altri schemi nell'architettura guidata dagli eventi e si mantengono elevate prestazioni.

Sentiti libero di sfidare la mia risposta! Potrebbe non piacerti quello che dico del tuo broker preferito con molte funzionalità sovrapposte, ma comunque, Kafka non è stato progettato come store di eventi, ma più come broker e buffer ad alte prestazioni allo stesso tempo per gestire produttori veloci rispetto a scenari di consumatori lenti, per esempio.

Consulta il framework open source eventuate.io microservices per scoprire di più sui potenziali problemi: http://eventuate.io/

Aggiornamento dall'8 febbraio 2018

Non incorporo nuove informazioni dai commenti, ma concordo su alcuni di questi aspetti. Questo aggiornamento riguarda alcuni consigli per la piattaforma basata sugli eventi microservizi. Se sei serio riguardo al design robusto del microservizio e alle massime prestazioni possibili in generale, ti fornirò alcuni suggerimenti che potrebbero interessarti.

  1. Non usare Spring - è fantastico (lo uso molto da solo), ma è pesante e lento allo stesso tempo. E non è affatto una piattaforma di microservizi. È "solo" un framework per aiutarti a implementarne uno (molto lavoro dietro questo ..). Altri framework sono "solo" REST o JPA leggeri o framework focalizzati diversamente. Raccomando probabilmente la migliore piattaforma completa di microservizi open source disponibile sul mercato che sta tornando alle radici Java pure: https://github.com/networknt

Se ti chiedi delle prestazioni, puoi confrontarti con la suite di benchmark esistente. https://github.com/networknt/microservices-framework-benchmark

  1. Non usare affatto Kafka :-)) È mezzo scherzo. Voglio dire, mentre Kafka è eccezionale, è un altro sistema incentrato sui broker. Penso che il futuro sia nei sistemi di messaggistica senza broker. Potresti essere sorpreso, ma ci sono più veloci dei sistemi Kafka :-), ovviamente devi scendere al livello inferiore. Guarda Chronicle.

  2. Per il negozio di eventi raccomando l'estensione Postgresql superiore denominata TimescaleDB, che si concentra sull'elaborazione dei dati della serie di servizi ad alte prestazioni (gli eventi sono serie di programmi) a grande volume. Naturalmente CQRS, il sourcing degli eventi (replay, ecc.) Sono integrati nel framework light4j, che utilizza Postgres come spazio di archiviazione ridotto.

  3. Per i messaggi, prova a consultare Coda cronologica, Mappa, Motore, Rete. Voglio dire sbarazzarsi di questo vecchio stile soluzioni di centric broker e andare con il sistema di micro messaggistica (uno incorporato). Chronicle Queue è in realtà anche più veloce di Kafka. Ma sono d'accordo che non è tutto in un'unica soluzione e devi fare un po 'di sviluppo altrimenti vai a comprare la versione Enterprise (una a pagamento). Alla fine lo sforzo di costruire da Chronicle il tuo livello di messaggistica verrà pagato rimuovendo l'onere della manutenzione del cluster Kafka.


Vista interessante Vuoi approfondire alcuni punti? > Kafka garantisce la consegna almeno una volta e ci sono duplicati nell'archivio eventi che non possono essere rimossi. Sembrerebbe implicare che esista esattamente una volta alla consegna. afaik (e ne sono abbastanza sicuro) non esiste una cosa del genere in un sistema distribuito. 2) Per quanto riguarda il punto 2: la scuola classica di (sourcing / dddd) del pensiero è che gli eventi sono intrinsecamente immutabili. Vale a dire: sono felici, non c'è modo di cambiare il passato. Qual è l'utile caso di cambiarli in retrospettiva? Grazie!
Geert-Jan

1.) Hazelcast per garantire che ogni messaggio venga elaborato una volta e una sola volta. 2.) Non mi piace niente come _V2 nel codice di servizio, quindi o eseguirai il backup per archiviare e ricreare i vecchi eventi nelle loro nuove versioni (hai ancora la verità originale), oppure puoi nascondere / creare questa funzionalità direttamente in Event Memorizza la funzionalità snapshot, quindi esiste un unico punto di upcasting -> l'archivio eventi. Quali sono le tue soluzioni a questo?
Kensai,

1) almeno una volta + idempotenza sul consumatore. Vale a dire: controlla se l'evento è già stato visto. Se è così salta. O meglio ancora, fai azioni idempotenti. Certo, questo non è sempre possibile. 2) Non ho mai incontrato la necessità di versioni eventi. Considero sempre gli eventi stessi come la fonte della verità e includo tutte le informazioni di cui avrei mai bisogno. In questo modo, non ho mai riscontrato una situazione in cui avevo bisogno di una diversa struttura di eventi e / o dati su un evento. Ma forse ymmv. Interessato a sapere in quali situazioni dovresti effettivamente avere eventi aggiornati.
Geert-Jan

1.) può essere la scelta preferita. 2.) quindi le tue strutture dati sono state perfette sin dall'inizio :-) fortunato, ahah. Potrei non averne bisogno sul mio attuale progetto, ma sto costruendo un'intera piattaforma su forcelle di eventuate.io fusa con alcuni approcci JEE ad alte prestazioni presi solo da light eventuate 4j ... tutta questa discussione non è il posto per commenti su StackOverflow , ma se sei interessato ad immergerti più in profondità, ti consiglio questo articolo: leanpub.com/esversioning/read
kensai,

1
A proposito, Kafka ora supporta esattamente una volta la consegna. Aggiorna
elenco

8

Sì, puoi usare Kafka come negozio di eventi. Funziona abbastanza bene, specialmente con l'introduzione di Kafka Streams , che fornisce un modo nativo di Kafka per elaborare i tuoi eventi nello stato accumulato che puoi interrogare .

Per quanto riguarda:

Possibilità di riprodurre il registro eventi che consente ai nuovi abbonati di registrarsi al sistema dopo il fatto.

Questo può essere difficile. L'ho trattato in dettaglio qui: https://stackoverflow.com/a/48482974/741970


0

Sì, Kafka funziona bene nel modello di approvvigionamento di eventi in particolare CQRS, tuttavia è necessario prestare attenzione durante l'impostazione dei TTL per gli argomenti e tenere sempre presente che Kafka non è stato progettato per questo modello, tuttavia è possibile utilizzarlo molto bene.


0

Penso che dovresti guardare al framework degli assoni insieme al loro supporto per Kafka

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.