Gestione delle modifiche in un'architettura di microservizi basata sugli eventi


9

Sto realizzando un progetto di ricerca in cui sto ricercando le opzioni per gestire i cambiamenti in un'architettura di microservizi basata sugli eventi.

Quindi, supponiamo di avere un'applicazione in cui abbiamo ottenuto quattro diversi servizi. Ognuno di questi servizi ha un proprio database per archiviare dati locali.

In questa configurazione, i quattro servizi comunicano tra loro utilizzando un bus eventi. Quindi quando succede qualcosa in un servizio, pubblica un evento. Tutti gli altri servizi interessati a quell'evento lo elaboreranno a modo loro.

In tal caso, i diversi servizi nell'architettura devono avere "contratti" sul contenuto di questi eventi (attributi, ecc.). Quindi i servizi hanno "dipendenze vagamente accoppiate" a questi eventi

La mia domanda è: come possiamo gestire i cambiamenti in questi eventi?

Quindi, diciamo che il servizio A registra nuovi utenti nell'applicazione. Quindi invia un evento "" Registrato dall'utente ". Il servizio B raccoglie quell'evento e lo elabora. Ma alcuni sviluppatori del team del servizio C hanno deciso di aver bisogno anche di un genere di utente registrato. Quindi l'evento è cambiato e l'attributo genere viene aggiunto all'evento "Registrato dall'utente".

Come possiamo assicurarci che il Servizio B possa ancora raccogliere lo stesso evento con quell'attributo extra senza ridistribuire?

E ci sono altri modi per affrontare questo problema, quindi il controllo delle versioni di questi eventi?


In che formato sono i tuoi messaggi o è qualcosa che puoi progettare? Alcuni formati di messaggi consentono attributi opzionali. A seconda dell'implementazione del lettore, è possibile aggiungere attributi opzionali senza dover aggiornare tutti i lettori.
Thomas Owens

Sono libero di scegliere un formato da utilizzare per i miei messaggi. Penso che usare JSON sia il modo migliore per andare. È importante che questi diversi servizi siano realizzati in diverse lingue. Ecco perché è necessario un formato generale come XML o JSON.
CGeense,

Risposte:


1

Gli eventi non riguardano ciò che è cambiato. Riguardano quando qualcosa è cambiato.

Posso creare un sistema di eventi completamente disaccoppiato dai contenuti che sono cambiati. In questo modo tutto ciò che imparo da un evento è che un oggetto è stato aggiornato. Se mi preoccupo anche che l'oggetto sia stato aggiornato, allora dirò a qualunque cosa sappia parlare con quell'oggetto per chiedergli cosa è cambiato.

Ciò non risolve il problema di comunicare questi cambiamenti. Impedisce semplicemente di diventare parte del sistema degli eventi.

Un esempio di un modo per risolvere il problema delle diverse versioni dei dati è che l'osservatore crei e distribuisca l'oggetto osservato in una raccolta. L'oggetto osservato popola la raccolta con i suoi dati più recenti e quando il controllo ti restituisce (l'osservatore) hai ciò di cui hai bisogno. Se c'è qualcosa in più che non ti interessa, perché non ne hai mai sentito parlare, semplicemente lo ignori.

Molti altri modi per scuoiare quel gatto, ma è quello che ho fatto funzionare esattamente in questo caso.


Ciò non aumenterebbe notevolmente il traffico tra i servizi? Utilizzando l'esempio nella domanda, un UserRegisteredevento, se ci fosse un evento che non conteneva informazioni sull'utente, ci sarebbe 1 messaggio pubblicato sul bus e quindi {numero di servizi interessati} richieste al servizio utente o messaggi pubblicati al bus. Quindi, ci sarebbero {numero di servizi interessati} messaggi di varie dimensioni. Anche se penso che questo sia probabilmente un design più pulito sulla carta, se le prestazioni sono un problema, si guastano in qualsiasi sistema non banale, specialmente su una rete.
Thomas Owens

@ThomasOwens Inviare dati con l'evento significa che se ho N osservatori invio N messaggi. L'invio dell'evento da solo significa che invio messaggi 3N solo 1 dei quali ha il pacchetto di dati. Ciò si adatta perfettamente anche su una rete. L'unico aspetto negativo significativo è che triplica il ritardo. Non dire che non puoi trovare una soluzione più ottimale per una situazione particolare. Sto dimostrando che i sistemi di eventi e le versioni dei dati non devono essere accoppiati.
candied_orange,

1
L'idea di questo bus di eventi è di disaccoppiare i diversi servizi. Usando un pezzo di middleware, possiamo assicurarci che questi servizi non si conoscano e possano esistere e comunicare senza conoscere l'esistenza reciproca. Se rimuoviamo lo stato da questi eventi e lasciamo che i servizi si colleghino direttamente tra loro, stiamo abbinando questi servizi. In questo modo, non possiamo mai riassegnare un singolo servizio senza dover ridistribuire il resto
CGeense,

1
Il punto qui è quel sistema di eventi o no hai bisogno di dati estensibili. JSON o XML lo fanno bene se non vai a cambiare i nomi o le strutture che sono state precedentemente stabilite. Ho fatto lo stesso con le raccolte. Il sistema degli eventi non dovrebbe interessarsi ai sessi. Se sta inviando dati, dovrebbe semplicemente passarli e qualcosa dall'altra parte si preoccuperà dei sessi o no.
candied_orange,

1

Framework come NServiceBus gestiscono questo problema utilizzando il versioning degli eventi con l'invio di messaggi polimorfici.

Ad esempio, la versione 1 del servizio A potrebbe pubblicare un evento come IUserRegistered_v1. Quando il servizio Una versione 1.1 deve includere un campo aggiuntivo, potrebbe dichiarare l'interfaccia IUserRegistered_v1_1, che erediterebbe da IUserRegistered_v1 e dichiarare alcuni campi aggiuntivi.

Quando il servizio A pubblica un evento IUserRegistered_v1_1, NServiceBus invierà il messaggio a tutti gli endpoint che gestiscono IUserRegistered_v1 o IUserRegistered_v1_1.


0

Miglioramento incrementale

Una semplice modifica al modello è che quando gli ascoltatori si registrano come osservatori, includono un elenco o altra struttura degli elementi di dati che desiderano conoscere. Questo può funzionare se i dati restituiti dal servizio sono semplici ma se si dispone di una discreta quantità di dati gerarchici, questo può essere davvero complicato da implementare.

Roccia solida

Se si desidera davvero un modo affidabile per eseguire questa progettazione del servizio in modo tale da conservare una cronologia delle modifiche apportate ai dati archiviati. In sostanza, non aggiorni mai i record nel tuo database, aggiungi nuovi record in cui ognuno rappresenta la modifica. Ognuno di questi nuovi record è associato a un ID evento che identifica l'azione. Un record pari viene archiviato con tutte le informazioni rilevanti sulla modifica (chi, cosa, quando, ecc.). Questo ha alcuni altri vantaggi che esulano dallo scopo di questa risposta ma sono discussi in questo articolo sul teorema della PAC .

Quando viene apportata una modifica, si crea il record dell'evento e si aggiungono tutti i nuovi dati al database. Quindi pubblichi un evento nei listener che contiene (in minima parte) l'id evento. I listener possono quindi richiedere i dati associati a quell'id e ottenere la versione dei dati ad esso associati. Ogni ascoltatore è quindi in grado di ottenere tutto ciò di cui ha bisogno senza accoppiare le esigenze di altri ascoltatori diversi insieme. Vorrei consigliare di aggiungere un sottoinsieme dei campi di dati più comunemente usati al messaggio dell'evento in modo che gli ascoltatori possano filtrare gli eventi a cui non sono interessati. Ciò può ridurre la chattiness del processo e alcuni ascoltatori potrebbero non aver mai bisogno di chiamare di nuovo a tutti. Questo ti protegge anche dai problemi di temporizzazione. Se ti basta richiamare il servizio e ottenere i dati in base alla chiave, potrebbero esserci altre modifiche tra il recupero dell'evento e il recupero dei dati per esso. Questo potrebbe non essere importante per tutti gli ascoltatori, ma può creare grossi problemi se è necessario conoscere tutte le modifiche. Il miglioramento della progettazione incrementale sopra è compatibile con questo approccio se si desidera davvero impostarlo su 11.

Parte di questo potrebbe essere eccessivo per quello che devi fare, ma nella mia esperienza, se non hai un modo preciso per vedere come un record sta cambiando nel tempo, tu o qualcuno che lavora con i tuoi dati alla fine lo desidererai.


-1

@CandiedOrange fa un punto valido in un commento alla propria risposta per quanto riguarda i formati di dati estensibili come xml.

Non dovrebbe importare finché aggiungi dati. Fornire impostazioni predefinite ragionevoli per eventi precedenti / campi non obbligatori, tuttavia.

Dovresti solo aggiornare i servizi che interessano, in questo caso, il genere. Un parser xml / json dovrebbe essere in grado di ignorare i dati extra per gli altri servizi. Ciò dipende ovviamente dalla scelta del parser e dal formato dei dati dell'evento.

Tuttavia, non sono d'accordo con gli eventi che non dispongono dei dati pertinenti. Per l'approvvigionamento di eventi, gli eventi dovrebbero definire ciò che è cambiato. Alla ricezione di un evento, altri servizi non dovrebbero recuperare i dati dalla fonte dell'evento.


Il mio punto è che deve gestire tutti i tipi di modifiche. Pensa a un servizio che trasmette un evento. E quell'evento contiene una proprietà che è obsoleta e dovrebbe essere rimossa. Anche se questi altri servizi non utilizzano la proprietà, li romperanno semplicemente perché lo stanno aspettando. Quindi ho letto questo articolo su martinfowler.com sui contratti guidati dai consumatori: martinfowler.com/articles/consumerDrivenContracts.html Quando si applica questo principio. Ogni fornitore (evento) sa cosa ci si aspetta da lui. con queste informazioni può convalidare se rompe qualsiasi cliente.
CGeense,
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.