CQRS, event sourcing e (quasi) report in tempo reale

2

Sto lavorando con un piccolo team che sta sviluppando un'architettura semi-microservice CQRS / ES. Siamo piuttosto avanti, ma con alcune sfide interessanti con le nostre proiezioni e ulteriori sfide stiamo iniziando a spostare le nostre proiezioni in un database di reportistica per gestire i problemi cross-domain Mi rendo conto che si tratta di problemi complessi e non esiste una soluzione adatta a tutte le dimensioni: è la prima volta che utilizzo un'architettura basata su eventi molto pesanti, quindi mi perdoni se sto usando alcuni termini sbagliati. è il motivo per cui sto avendo difficoltà a trovare ulteriori informazioni per affrontare queste sfide. Non mi aspetto che qualcuno possa risolvere questi problemi per me, ma sarei molto grato per l'aiuto con la terminologia e se potessi indicarmi qualsiasi risorsa che possa essere utile per i problemi che illustrerò qui sotto. Grazie in anticipo!

Bene, io e il mio team stiamo costruendo software che ha diversi servizi. Ogni servizio utilizza un'architettura CQRS, eventing e alcune entità sono di origine evento. Le entità che sono state originate da eventi sono di origine evento perché ci sono dipendenze da versioni specifiche di tali entità. La nostra architettura degli eventi di dominio è strongmente ispirata da "Implementing Domain-Driven Design" di Vaughn Vernon. Ogni servizio ha il proprio database relazionale o almeno il proprio schema che viene trattato come un database separato. Ogni database ha una tabella degli eventi di dominio con un vincolo sull'aggregato e sul numero di versione per garantire che una transazione non riesca se due eventi arrivano contemporaneamente per la stessa entità. Questa è un'applicazione strongmente collaborativa, quindi questo è molto importante per noi.

Problema 1:

Attualmente pubblichiamo i nostri eventi di dominio per gli abbonati. Gli abbonati sono attualmente limitati al servizio stesso e di solito sono proiezioni. Abbiamo provato a pubblicare l'evento dopo che una transazione è stata elaborata correttamente, in modo che gli eventi possano essere elaborati in modo asincrono senza bloccare l'utente, ma ciò ha comportato la mancata elaborazione degli eventi. Ora elaboriamo la maggior parte degli eventi all'interno della transazione. Funziona per ora perché la logica di gestione delle proiezioni avviene molto rapidamente, ma potrebbe non essere il caso per molto tempo. Le proiezioni non devono essere aggiornate in tempo reale, ma devono essere aggiornate quasi in tempo reale. Probabilmente possiamo prevedere ritardi fino a 2 o 3 secondi. In che modo l'ordine degli eventi è generalmente garantito in questo scenario?

Problema # 2:

Stiamo iniziando a richiedere un ordinamento e un filtro complessi sulle viste che combinano i dati di diversi servizi che sembra richiedere il passaggio della nostra logica di proiezione in un servizio di report separato. Abbiamo esaminato alcuni modelli diversi, come i meccanismi basati su push o i meccanismi basati su pull ispirati a Kafka, ma stiamo avendo difficoltà a determinare in che modo ottenere gli eventi da ciascun servizio e quindi come possiamo elaborarli in ordine, per aggregato, nel nostro servizio di segnalazione (soprattutto se stiamo eseguendo più istanze del nostro servizio di segnalazione). Riconosciamo che, in base alla nostra configurazione corrente, possiamo garantire l'ordine solo all'interno dei servizi e non tra i servizi, ma ciò è accettabile poiché prevediamo che queste operazioni siano commutative in quel (the aggregate of 4 events from service 1).aggregatedWith(the aggregate of 5 events from service 2) == (the aggregate of 5 events from service 2).aggregatedWith(the aggregate of 4 events from service 1) . Anche qui lo stesso ritardo di 2-3 secondi è accettabile. Qualsiasi risorsa o termine di ricerca su questo tipo di problema (o eventuali suggerimenti alternativi) sarebbe molto apprezzato!

    
posta Jordan 03.01.2018 - 16:02
fonte

2 risposte

3

ascolta i discorsi di Greg Young su dati Polyglot ; potrebbe persuaderti che desideri un modello pull, piuttosto che un modello push, per i tuoi abbonamenti.

Essenzialmente, quando l'abbonamento "si sveglia", aggiorna la sua copia locale della cronologia degli eventi / storia dal libro del record, e quindi scrive la nuova proiezione da quelle storie.

Se memorizzi i metadati con la proiezione, puoi tenere traccia del punto in cui sei rimasto, il che può ridurre la quantità di informazioni ridondanti recuperate dal libro dei record (supponendo che supporti le query a distanza).

Fondamentalmente, il libro dei record è un database, non un servizio (il "servizio" è responsabile della pubblicazione delle modifiche al libro dei record). Si ottengono eventi da ciò inviando una query. Probabilmente non invierai le query direttamente al libro dei record; il vero database in uso è un dettaglio di implementazione che potresti voler cambiare e, in ogni caso, probabilmente è indipendente dal dominio. Il tuo database (che supporta query specifiche per dominio) è una facciata davanti all'appliance di persistenza che hai scelto.

    
risposta data 03.01.2018 - 18:02
fonte
1

Suggerirei di esaminare il modello di attore . L'utilizzo di questo modello potrebbe probabilmente risolvere entrambi i problemi attuali e aiutare a standardizzare la progettazione e ridurre i problemi futuri con la crescita del numero di consumatori di eventi e la diversificazione dei consumatori. Usare un Actor Framework, come Akka o Akka.net, potrebbe anche essere molto utile, ma potresti essere troppo avanti nella tua implementazione per apportare un cambiamento architettonico così significativo.

Essenzialmente, ciascun attore è responsabile di una cosa (ad esempio una proiezione specifica) e ha una casella di posta dedicata (coda di messaggi) per gli eventi che deve elaborare. Gli attori elaborano un messaggio alla volta, quindi la semantica di accodamento dei messaggi standard garantisce l'elaborazione in ordine, poiché ogni cassetta postale ha un solo consumatore (l'attore stesso), indipendentemente da come viene implementata la cassetta postale (RabbitMQ, Kafka, coda in memoria, eccetera.). Una volta deciso come implementare i tuoi attori, devi solo assicurarti che gli eventi vengano scritti dal giornale eventi (la tabella degli eventi di dominio) nelle cassette postali degli attori nello stesso ordine in cui sono impegnati nel giornale eventi. Risolvere questo problema una volta (ottenendo gli eventi dal diario alle cassette postali in ordine) lo risolverebbe in tutti i casi, poiché tutti i consumatori sarebbero attori.

    
risposta data 03.01.2018 - 17:18
fonte

Leggi altre domande sui tag