Microservizi senza duplicazione dei dati


19

Sto trovando difficile evitare la duplicazione dei dati o un database condiviso anche per la progettazione dei microservizi più semplice, il che mi fa pensare che mi manchi qualcosa. Ecco un esempio di base del problema che sto affrontando. Supponendo che qualcuno stia utilizzando un'applicazione Web per gestire un inventario, avrebbero bisogno di due servizi; uno per l'inventario che gestisce gli articoli e la quantità in magazzino e un servizio utenti che gestirà i dati degli utenti. Se vogliamo un controllo su chi ha immagazzinato il database, potremmo aggiungere l'ID utente al database per il servizio di inventario come ultimo fornito per valore.

Utilizzando l'applicazione potremmo voler vedere tutti gli articoli che stanno per esaurirsi e un elenco di chi li ha immagazzinati l'ultima volta in modo da poter chiedere loro di rifornirlo di nuovo. Usando l'architettura sopra descritta, verrà inviata una richiesta al servizio di inventario per recuperare i dettagli dell'articolo di tutti gli articoli in cui la quantità è inferiore a 5. Ciò restituirebbe un elenco che include gli ID utente. Quindi verrà inviata una richiesta separata al servizio utenti per ottenere il nome utente e i dettagli di contatto per l'elenco degli ID utente ottenuti dal servizio di inventario.

Questo sembra terribilmente inefficiente e non ci vogliono molti più servizi prima di effettuare più richieste a API di servizi diversi che a loro volta eseguono più query sul database. Un'alternativa è replicare i dettagli degli utenti nei dati di inventario. Quando un utente modifica i propri dati di contatto, è necessario replicare la modifica tramite tutti gli altri servizi. Ma questo non sembra adattarsi all'idea di contesto limitato dei microservizi. Potremmo anche utilizzare un singolo database e condividerlo tra diversi servizi e avere tutti i problemi di un database di integrazione .

Qual è il modo corretto / migliore per implementarlo?


5
Benvenuti nel paradosso dei micro-servizi. Ciò che sembrerebbe semplificare le cose può effettivamente rendere le cose più complesse.
Robert Harvey,

Il modo "corretto" è lo stesso di sempre: capire un modo di fare le cose che si adattano meglio ai tuoi obiettivi specifici.
Robert Harvey,

1
@RobertHarvey È sempre così, ma sto cercando di capire il modo dei microservizi del libro di testo. Una volta capito come dovrebbe funzionare in un mondo ideale, lo cambierò felicemente per adattarlo al mio caso d'uso.
Geraint Anderson,

1
Ma inquadra la tua domanda in termini di efficienza, che è un requisito software non funzionale. Il modo in cui risolvi il problema dell'efficienza è chiedendo direttamente al database.
Robert Harvey,

1
Stavo per scrivere una domanda esattamente come la tua. Non vedo ancora vantaggi in MSA per applicazioni web ragionevolmente semplici. Penso che in molti casi la modularità potrebbe essere raggiunta senza rendere le cose così complesse.
Glasnhost,

Risposte:


10

Ho completamente perso dove ti viene richiesto di duplicare.

Un principio centrale dei microservizi è che il servizio sia l'autorità unica. Ciò significa che l'inventario e la gestione degli utenti possono essere completamente separati. Progetterei la gestione degli utenti in modo che non sappia nemmeno che esiste il sistema di inventario.

Ma progetterei il sistema di inventario in modo che non memorizzi mai nulla di utenti diverso da un ID utente. Ciò risolve il problema della propagazione delle modifiche alle informazioni utente.

Per quanto riguarda le cose che richiedono informazioni sull'inventario e informazioni sull'utente come registri, audit e stampe, non vengono aggiornate quando cambiano le informazioni. Sono un registro di ciò che era. Ancora una volta, non propagare il cambiamento.

Quindi, in ogni caso, quando si desidera le informazioni utente più recenti, si chiede al servizio informazioni utente.


@Geraint: puoi essere più specifico su quale tipo di duplicazione si sta verificando nel tuo sistema?
Robert Harvey,

1
Grazie. La duplicazione si riferiva alla copia dei dettagli di contatto degli utenti nel servizio di inventario, ma tu l'hai indirizzata (cioè non è richiesta). Sembra contro intuitivo passare da un singolo database relazionale in cui ho potuto ottenere i dati di inventario e i dati utente con un join per effettuare due chiamate API distinte in cui la seconda non può iniziare fino a quando la prima non ha restituito i risultati. Ma immagino che faccia parte della valutazione se uso microservizi o qualcos'altro.
Geraint Anderson,

È lo stesso trucco che il DB userebbe se gestisse entrambi. Non copiare le informazioni utente nella tabella di inventario. Gli dai una chiave esterna. L'ID utente sta facendo lo stesso lavoro tra i servizi. Renderlo unico.
candied_orange

It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a joinTieni presente che "idealmente" c'è un negozio per servizio (o più!). Quindi, non c'è niente come "unire" tra "confini". Il motivo è semplice, DB genera l'accoppiamento tra i servizi. A differenza di quanto suggerito da @CandiedOrange, penso che possiamo duplicare un minimo di dati da un servizio all'altro. Mi riferisco a dati che è improbabile che cambino. Se questo dups migliora l'efficienza e le prestazioni (ed entrambi sono necessari), i "professionisti" probabilmente compenserebbero i "contro"
Laiv

@GeraintAnderson Voglio dire, se hai bisogno di efficienza (che è per definizione un requisito non funzionale), ci sono modi per farlo. Vale a dire richiedere pagine di dati dal Servizio inventario (come 10 elementi), prendere ogni pagina e usare quella pagina per richiedere dati al Servizio utenti e aggregare alla fine. In questo modo mantieni i tuoi confini sfruttando il parallelismo dei servizi indipendenti. Anche in questo caso, non preoccuparti finché non l'hai identificato come un vero collo di bottiglia dell'applicazione che deve essere risolto: aspettare un altro secondo e mezzo su un lavoro notturno di 1 secondo non è importante per nessuno.
Delioth

11

Sto trovando difficile evitare la duplicazione dei dati ....

Secondo l' ebook Microsoft sull'architettura dei microservizi , non c'è nulla di sbagliato nella duplicazione dei dati. Fondamentalmente, la duplicazione dei dati aumenta il disaccoppiamento tra i servizi e quindi rafforza il loro ruolo di singola autorità. Un passaggio rilevante:

E infine (ed è qui che sorgono la maggior parte dei problemi quando si creano microservizi), se il microservizio iniziale necessita di dati che sono originariamente di proprietà di altri microservizi, non fare affidamento su richieste sincrone per tali dati. Invece, replicare o propagare quei dati (solo gli attributi necessari) nel database del servizio iniziale utilizzando l'eventuale coerenza (in genere utilizzando gli eventi di integrazione ...


1
Non sono completamente d'accordo. Rende più difficile da mantenere. Ti consente di implementare transazioni tra microservizi quando qualcosa deve essere aggiunto, aggiornato o rimosso. Nel caso in cui si desideri impedire un singolo punto di errore, è possibile utilizzare la richiesta o qualsiasi altro tipo di memorizzazione nella cache.
Alan Sereb,

1
@AlanSereb È più difficile da mantenere, ma il punto è che a volte non hai altra scelta. Ad esempio, cosa succede se è necessario creare un FK tra oggetti che vivono in due database? L'unico modo per garantire coerenza quando si eseguono query in un DB locale è disporre di una replica dei dati. Dai un'occhiata a: stackoverflow.com/a/4452586/2255491
David D.

Sono d'accordo. Un altro ottimo approccio è quello di prendere la strada di approvvigionamento dell'evento. E
fai

4

verrebbe fatta una richiesta al servizio di inventario per recuperare i dettagli dell'articolo di tutti gli articoli in cui la quantità è inferiore a 5. Ciò restituirebbe un elenco che include gli ID utente. Quindi verrà inviata una richiesta separata al servizio utenti per ottenere il nome utente e i dettagli di contatto per l'elenco degli ID utente ottenuti dal servizio di inventario.

Si, certo.

Concesso, in un monolite potresti avere un modello di inventario che richiedi gli articoli pertinenti, inserirlo in un modello utente e ottenere gli stessi dati.

Oppure potresti prenderlo ulteriormente, se li hai nello stesso database relazionale e scrivi SQL che e il database prenderà la tabella di inventario e la tabella utente, fa un po 'di magia e ottieni i dati che stai cercando.

Indipendentemente da come lo fai, da qualche parte lì sarà del codice che essenzialmente recupera un elenco di ID utente dal sistema di inventario, li inserisce nel sistema utente e compila un elenco di dati.

La domanda a cui devi rispondere riguarda prestazioni e manutenzione e altre qualità "leggere".

Il principale vantaggio dei microservizi è il ridimensionamento. Se hai diecimila utenti su una macchina ed è un po 'lento, puoi aggiungere un'altra macchina e il sistema diventa il doppio più veloce. Aggiungine altri otto ed è dieci volte più veloce. (Il ridimensionamento lineare è probabilmente ottimistico, ma è l'ideale e non quello irragionevole da sperare.)

E questo è per servizio . Se il sistema di inventario è il collo di bottiglia, viene utilizzato per più di report sugli utenti, è possibile aggiungere più macchine solo a quel servizio . Le macchine possono anche essere specializzate; questo servizio richiede molta memoria, il servizio esegue calcoli pesanti e necessita di più CPU.

Se non hai bisogno del ridimensionamento, c'è un altro vantaggio dei microservizi: sono modulari . Certo, anche le app monolitiche possono essere modulari e hai un database normalizzato e ... ma in pratica le pareti tra i moduli sono come pareti di vetro nel migliore dei casi e le linee nella sabbia nel peggiore. I microservizi sono separati da acciaio solido.

Se il tuo sistema utente prende letteralmente fuoco, ciò non influirà minimamente sul tuo sistema di inventario. Non sarai in grado di stampare graziosi rapporti su chi ha immagazzinato cosa, ma i clienti saranno in grado di effettuare ordini sicuri sapendo che gli articoli immagazzinati sono lì.

E non duplicate i dati nei microservizi , non più di quanto facciate in un database relazionale (*). In un database relazionale è possibile eseguire un join e l'equivalente è unire gli elenchi in codice come descritto.

Potresti anche aggiungere una vista , l'equivalente è aggiungere un nuovo servizio che fa l'unione per te; ciò comporterebbe tre richieste; uno al nuovo servizio e quindi quel servizio fa i due originali. I database relazionali hanno elementi fantasiosi che ottimizzano le viste, che devono essere implementati a livello di servizio. Non lo ottieni "gratuitamente".

La memorizzazione nella cache è diversa dalla duplicazione dei dati in quanto se due valori non corrispondono, sai quale è sbagliato. Viene spesso utilizzato nei microservizi per aumentare la disponibilità a scapito della coerenza (teorema della PAC). Poiché i database relazionali macellano completamente la disponibilità sull'altare della coerenza, è meno comune in essi. Direi che non c'è nulla di inerente ai microservizi che semplifichi la memorizzazione nella cache, ma in pratica la memorizzazione nella cache è una preoccupazione primaria e che semplifica la memorizzazione nella cache nei microservizi .

(*) Se ha senso duplicare i dati in uno sciame di microservizi, probabilmente avrebbe senso nel database relazionale equivalente a.


3
Mi è piaciuta molto la tua risposta fino alla parte "non duplicare i dati nei microservizi". Penso che ci siano casi in cui la duplicazione dei dati è l'approccio giusto. Migliora la tolleranza agli errori e l'autonomia. Se il servizio utenti è inattivo, il servizio di inventario può comunque visualizzare un elenco di inventario basso con chi li ha immagazzinati per ultimi.
Pietro Pompei,

1
@peterpompeii La chiamerei cache, non duplicazione dei dati. La duplicazione dei dati avviene quando si dispone di due posizioni da aggiornare per un dato, memorizzazione nella cache quando esiste una posizione e propagazione automatica nelle altre posizioni. Inoltre ho detto più che relazionale. Se ha senso duplicare i dati in un database relazionale, ha senso in un microservizio. Penso che siamo d'accordo e che parte potrebbe essere più chiara, ma al momento ho solo un telefono, quindi non aggiornerò il testo adesso.
Odalrick,

@PeterPompeii Spero che la sezione aggiunta sulla memorizzazione nella cache risolva alcuni dei tuoi dubbi.
Odalrick,

1
@Odalrick quello che hai descritto sembra una replica dei dati. La replica e la memorizzazione nella cache sono entrambe forme di duplicazione dei dati. La replica è quando una copia è garantita per avere sempre tutti i dati necessari. La memorizzazione nella cache è su richiesta. La memorizzazione nella cache può avere una mancanza. La memorizzazione nella cache per la disponibilità non ha lo stesso senso della memorizzazione nella cache per le prestazioni. TL; DR se stai memorizzando una copia completa di qualcosa con sufficiente coerenza garantisce che non devi mai controllare la presenza di errori, quindi non è una cache.
Brandon,

1
@Brandon Un'altra differenza tra replica e memorizzazione nella cache è il modo in cui sai quali dati sono errati quando c'è una differenza. La replica definisce alcune regole su come unire i dati. La cache invece è sempre : la cache è sbagliata.
Odalrick,
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.