Perché è così male leggere i dati da un database "di proprietà" di un microservizio diverso


64

Di recente ho letto questo eccellente articolo sull'architettura dei microservizi: http://www.infoq.com/articles/microservices-intro

Indica che quando carichi una pagina web su Amazon, oltre 100 microservizi collaborano per servire quella pagina.

Questo articolo descrive che tutte le comunicazioni tra microservizi possono passare solo attraverso un'API. La mia domanda è perché è così brutto dire che tutte le scritture di database possono passare solo attraverso un'API, ma sei libero di leggere direttamente dai database dei vari micro-servizi. Si potrebbe ad esempio affermare che solo alcune visualizzazioni del database sono accessibili al di fuori del micro-servizio in modo che il team che gestisce il micro-servizio sappia che finché mantengono intatte queste visualizzazioni possono cambiare la struttura del database del loro micro-servizio volere.

Mi sto perdendo qualcosa qui? C'è qualche altro motivo per cui i dati devono essere letti solo tramite un'API?

Inutile dire che la mia azienda è significativamente più piccola di Amazon (e lo sarà sempre) e il numero massimo di utenti che possiamo mai avere è di circa 5 milioni.


Un altro fattore generale non menzionato nelle risposte è che quando si scrive nel database, la memorizzazione nella cache locale, anche la semplice mappatura O, può produrre dati non aggiornati quando si accede immediatamente al database. Se si considera di bypassare l'API µservice per motivi di velocità, è possibile che l'architettura µservice sia andata troppo oltre.
Joop Eggen,

Quando si consente la lettura del database, ogni dettaglio del database diventa parte dell'API pubblica. Non vorrei mantenere la compatibilità su un'API così complessa.
Patrick,

Ma in quel caso la vista non diventa semplicemente parte dell'API, almeno per scopi semantici? È solo una questione di ciò che stai chiamando l'API e di ciò che ti obbliga a mantenere. (Di solito un livello sopra il database è più facile da mantenere coerente.)
lc.

Sono d'accordo che la vista sarebbe semplicemente una forma di API. Penso che la maggior parte delle persone che rispondono a questa domanda non leggano la mia idea sull'uso delle viste come livello di astrazione. Capisco, anche se mantenere intatta la vista se si cambia la tecnologia del database sarebbe una grande sfida, ma sono disposto a scommettere sul fatto che non avremo bisogno di cambiare la nostra tecnologia di database per i prossimi 5 anni. Inoltre, le prestazioni non saranno un problema con soli 5 utenti del mulino. Quindi, date le nostre dimensioni, ringrazio che cercherò questa soluzione, anche se le risposte qui sembrano indicare che sto andando dritto in un mondo di dolore.
David,

Risposte:


69

I database non sono molto bravi a nascondere le informazioni, il che è abbastanza plausibile, perché il loro compito è quello di esporre effettivamente le informazioni. Ma questo li rende uno strumento scadente quando si tratta di incapsulamento. Perché vuoi l'incapsulamento?

Scenario: si collegano direttamente un paio di componenti a un RDBMS e si vede un particolare componente diventare un collo di bottiglia delle prestazioni per il quale si potrebbe voler denormalizzare il database, ma non è possibile perché tutti gli altri componenti ne risentirebbero. Potresti persino capire che staresti meglio con un archivio documenti o un database grafico che con un RDBMS. Se i dati sono incapsulati da una piccola API, hai una possibilità realistica di reimplementare detta API in qualsiasi modo ti serva. È possibile inserire in modo trasparente livelli di cache e cosa no.

Il frugare nello strato di memoria direttamente dal livello dell'applicazione è l'opposto diametrale di ciò che il principio di inversione di dipendenza suggerisce di fare.


1
Questo è un ottimo punto! Una cosa che mi rende meno preoccupato è che Postgres ora supporta sia l'archivio documenti che RDBMS ( senzatheloop.com/articles/2014-09-30-postgresql-nosql ). Il tuo punto è comunque valido e lo prenderò in considerazione attentamente.
David,

3
@David non dovrebbe farti preoccupare solo perché uno strumento può fare qualcosa non significa che cambiarlo non si romperà molte cose. Questo è il punto di avere un certo grado di separazione: puoi cambiare completamente i dati dietro un'API senza cambiare ciò che l'utente vede. Sto parlando come un databaser qui ... fintanto che ciò che il cliente vede è lo stesso, puoi cambiare il backend quanto vuoi.
Ben

1
@David Anche se questa è una notizia interessante, è abbastanza irrilevante per lo scenario che ho descritto. Se modifichi il tuo schema DB da relazionale a uno basato su documento, avrà lo stesso impatto su tutti quelli che dipendono da esso: dovrai riscrivere tutte le query. C'è anche l'incubo di dover implementare tutte queste modifiche contemporaneamente, in modo che la compatibilità tra i componenti sia mantenuta in tutto il sistema.
back2dos,

1
@David: Limitare l'accesso ad alcune viste ben definite significa probabilmente costruire un'altra API, con alcuni dei vantaggi che ne derivano. Finché si tratta solo di visualizzazioni, sei comunque limitato all'accesso in sola lettura. E avere un componente dipende sia dall'API di servizio che dall'API di visualizzazione lo rende molto fragile. Quindi, se stai facendo dipendere un componente dalle viste, hai predeterminato che sia di sola lettura o di alta manutenzione. Sento odore di debito tecnico qui. Inoltre, potresti voler aggiungere il partizionamento orizzontale in modo che il tuo database non ti permetta.
back2dos,

2
@David: a lungo termine è più importante quanto sia facile cambiare il codice di quanto sia facile scriverlo. L'architettura non dice "non dovresti scrivere codice in questo modo", dice "se lo fai, subirai terribili incubi nel tentativo di mantenerlo". Se stai parlando di prototipi, la manutenzione non è un requisito. Vai avanti. Un prototipo dovrebbe dimostrare un punto il più facilmente possibile. Ma quando si tenta di integrare tutti i punti comprovati in un sistema senza farlo devolvere nella tortura autoindotta di Sisifo, è meglio andare oltre.
back2dos,

55

Cosa c'è di più importante e significativo in un microservizio: la sua API o il suo schema di database? L'API, perché questo è il suo contratto con il resto del mondo. Lo schema del database è semplicemente un modo conveniente per archiviare i dati gestiti dal servizio, si spera sia organizzato in modo da ottimizzare le prestazioni del microservizio. Il team di sviluppo dovrebbe essere libero di riorganizzare quello schema - o passare a una soluzione di archivio dati completamente diversa - in qualsiasi momento. Al resto del mondo non dovrebbe interessare. Al resto del mondo importa quando l'API cambia, perché l'API è il contratto.

Ora, se vai a sbirciare nel loro database

  • Si aggiunge una dipendenza indesiderata al loro schema. Non possono cambiarlo senza avere un impatto sul tuo servizio.
  • Aggiungete un carico indesiderato e imprevedibile ai loro interni.
  • Le prestazioni del proprio servizio saranno influenzate dalle prestazioni del loro database (cercheranno di ottimizzare il loro servizio per ottenere buone prestazioni per i clienti e il loro database per funzionare bene solo per il loro servizio)
  • Stai legando la tua implementazione a uno schema che potrebbe non rappresentare in modo accurato e distintivo le risorse nel loro archivio di dati - potrebbe avere ulteriori dettagli che sono necessari solo per tracciare lo stato interno o soddisfare la loro particolare implementazione (di cui non dovresti preoccuparti).
  • Puoi involontariamente distruggere o corrompere lo stato del loro servizio (e non sapranno che lo stai facendo)
  • Puoi aggiornare / cancellare / rimuovere risorse dal loro database senza che loro sappiano che è successo.

Gli ultimi due punti potrebbero non accadere se ti viene concesso solo l'accesso in lettura, ma gli altri punti sono più che un motivo sufficiente. I database condivisi sono una brutta cosa.

È comune per gli sviluppatori meno esperti (o coloro che non imparano) vedere il database come più importante del servizio, vedere il database come la cosa reale e il servizio solo un modo per accedervi. Questa è la strada sbagliata.


4
Tutti i punti sopra riportati sono validi anche se sei l'unico sviluppatore a lavorare sull'intero progetto. La gestione di un progetto complesso, anche da solo, evoca tutte queste preoccupazioni.
itsbruce,

15

L'architettura dei microservizi è difficile da descrivere, ma il modo migliore per pensarci è un matrimonio tra architettura orientata ai componenti e architettura orientata ai servizi. Il software come suite è composto da molti componenti di piccole imprese con una responsabilità di dominio aziendale molto specifica. La loro interfaccia con il mondo esterno nei servizi forniti o nei servizi richiesti avviene tramite un'API di servizi chiaramente definiti.

Scrivere e persino leggere da un database esterno al dominio aziendale dei componenti è contro questo stile di architettura.

Il motivo principale di ciò è che un'API fornita tramite un servizio da un altro componente software ha la ragionevole aspettativa che l'API sarà molto probabilmente retrocompatibile quando saranno disponibili nuove versioni del componente che fornisce il servizio. Se sono lo sviluppatore di un componente "fornente", mi devo solo preoccupare della retrocompatibilità con la mia API. Se so che ci sono altri tre team di sviluppo che hanno scritto direttamente query personalizzate sul mio database, il mio lavoro è diventato molto più complicato.

Ancora peggio, forse quell'altro team che ha scritto questi è uno sprint a metà in un progetto critico e non possono accettare questo cambiamento ora dal tuo componente. Ora lo sviluppo di software per il tuo componente su un dominio aziendale di tua proprietà è guidato dallo sviluppo su un altro dominio aziendale.

La piena interazione attraverso i servizi riduce l'accoppiamento tra i vari componenti software, quindi situazioni come questa non si verificano così frequentemente. Quando si tratta di altri componenti che utilizzano una vista nel database, allora si ha più possibilità di rendere compatibile la vista all'indietro se qualcun altro ha scritto delle domande a riguardo. Sento comunque che questo dovrebbe essere il caso eccezionale e dovrebbe essere fatto solo per la segnalazione o l'elaborazione in batch in cui un'applicazione dovrà leggere enormi quantità di dati.

Chiaramente questo funziona bene in grandi team distribuiti in cui i team di sviluppo sono separati da domini aziendali come Amazon. Se sei un piccolo negozio di sviluppo puoi comunque trarre vantaggio da questo modello, soprattutto se devi accelerare rapidamente per un grande progetto, ma anche se devi occuparti del software del fornitore.


4

Negli ultimi 20 anni ho visto alcuni grandi progetti di database modulari e ho visto lo scenario suggerito da David parecchie volte ora in cui le applicazioni hanno accesso in scrittura al proprio schema / set di tabelle e accesso in lettura a un altro schema / set di tavoli. Molto spesso questi dati a cui un'applicazione / modulo ottengono l'accesso in sola lettura potrebbero essere descritti come "dati principali" .

In quel momento non ho visto i problemi suggeriti dalle risposte precedenti, quindi penso che valga la pena dare un'occhiata più da vicino ai punti sollevati nelle risposte precedenti in modo più dettagliato.

Scenario: leghi direttamente un paio di componenti a un RDBMS e vedi un particolare componente diventare un collo di bottiglia prestazionale

Sono d'accordo con questo commento, tranne per il fatto che questo è anche un argomento per avere una copia dei dati localmente per la lettura del microservizio. Cioè, la maggior parte dei database maturi supporta la replica e quindi, senza alcuno sforzo dello sviluppatore, i "dati principali" possono essere replicati fisicamente nel database dei microservizi se ciò è desiderato o necessario.

Alcuni potrebbero riconoscerlo come un "database aziendale" replicando le tabelle core in un "database dipartimentale". Un punto qui è che in genere è buono se un database lo fa per noi con la replica integrata dei dati modificati (solo delta, in forma binaria e con costi minimi per il database di origine).

Al contrario, quando le nostre scelte di database non consentono questo supporto di replica "standardizzato", possiamo entrare in una situazione in cui vogliamo spingere "dati anagrafici" nei database dei microservizi e questo può comportare una notevole quantità di sforzi degli sviluppatori e essere anche un meccanismo sostanzialmente meno efficiente.

potrebbe voler denormalizzare il database, ma non è possibile perché tutti gli altri componenti ne risentirebbero

Per me questa affermazione non è corretta. La denormalizzazione è un cambiamento "additivo" e non un "cambiamento di rottura" e nessuna applicazione dovrebbe rompersi a causa della denormalizzazione.

L'unico modo in cui un'interruzione di un'applicazione è in cui il codice dell'applicazione utilizza qualcosa come "select * ..." e non gestisce una colonna aggiuntiva. Per me sarebbe un bug nell'applicazione?

In che modo la denormalizzazione può interrompere un'applicazione? Mi sembra FUD.

Dipendenza dallo schema:

Sì, l'applicazione ora ha una dipendenza dallo schema del database e la conseguenza è che questo dovrebbe essere un grosso problema. Mentre l'aggiunta di qualsiasi dipendenza aggiuntiva non è ovviamente l'ideale, la mia esperienza è che una dipendenza dallo schema del database non è stata un problema, quindi perché potrebbe essere così? Sono stato solo fortunato?

Dati anagrafici

Lo schema a cui normalmente vorremmo che un microservizio avesse accesso in sola lettura è più comunemente quello che definirei " dati anagrafici " per l'impresa. Ha i dati di base essenziali per l'impresa.

Storicamente questo significa che lo schema su cui aggiungiamo la dipendenza è maturo e stabile (un po 'fondamentale per l'impresa e immutabile).

Normalizzazione

Se 3 progettisti di database vanno e progettano uno schema db normalizzato, finiranno con lo stesso design. Ok, potrebbe esserci qualche variazione 4NF / 5NF ma non molto. Inoltre, ci sono una serie di domande che il designer può porre per convalidare il modello in modo che il designer possa essere sicuro di essere arrivato a 4NF (sono troppo ottimista? Le persone che lottano per arrivare a 4NF?).

aggiornamento: Per 4NF qui intendo che tutte le tabelle nello schema sono arrivate alla loro forma normale più alta fino a 4NF (tutte le tabelle sono state normalizzate in modo appropriato fino a 4NF).

Credo che il processo di progettazione della normalizzazione sia il motivo per cui i progettisti di database sono generalmente a proprio agio con l'idea di dipendere da uno schema di database normalizzato.

Il processo di normalizzazione porta il design del DB a un design "corretto" noto e le variazioni da lì dovrebbero essere denormalizzazione per le prestazioni.

  1. Possono esserci variazioni in base ai tipi di DB supportati (JSON, ARRAY, tipo di supporto geografico ecc.)
  2. Alcuni potrebbero argomentare per una variazione basata su 4NF / 5NF
  3. Escludiamo la variazione fisica (perché non importa)
  4. Limitiamo questo al design OLTP e non al design DW perché quelli sono gli schemi a cui vogliamo garantire l'accesso in sola lettura

Se a 3 programmatori fosse assegnato un progetto da implementare (come codice) l'aspettativa sarebbe per 3 diverse implementazioni (potenzialmente molto diverse).

Per me esiste potenzialmente una questione di "fede nella normalizzazione".

Rompere le modifiche allo schema?

La denormalizzazione, l'aggiunta di colonne, l'alterazione di colonne per l'archiviazione più ampia, l'estensione del design con nuove tabelle ecc. Sono tutte modifiche non interruttive e i progettisti di DB che sono arrivati ​​al 4 ° modulo normale ne saranno certi.

È ovviamente possibile interrompere le modifiche eliminando colonne / tabelle o apportando una modifica al tipo di interruzione. Possibile sì, ma in termini pratici non ho riscontrato alcun problema qui. Forse perché si capisce quali sono i cambiamenti di rottura e questi sono stati ben gestiti?

Sarei interessato a sentire casi di interruzione delle modifiche dello schema nel contesto di schemi condivisi di sola lettura.

Cosa c'è di più importante e significativo in un microservizio: la sua API o il suo schema di database? L'API, perché questo è il suo contratto con il resto del mondo.

Mentre sono d'accordo con questa affermazione, penso che ci sia un avvertimento importante che potremmo sentire da un Enterprise Architect che è "Data vive per sempre" . Cioè, mentre l'API potrebbe essere la cosa più importante, i dati sono anche piuttosto importanti per l'impresa nel suo insieme e saranno importanti per molto tempo.

Ad esempio, una volta che è necessario popolare Data Warehouse for Business intelligence, lo schema e il supporto CDC diventano importanti dal punto di vista del reporting aziendale indipendentemente dall'API.

Problemi con le API?

Ora, se le API fossero perfette e facili, tutti i punti sarebbero controversi, dato che sceglieremmo sempre un'API anziché avere accesso locale in sola lettura. Quindi la motivazione per considerare anche l'accesso di sola lettura locale è che potrebbero esserci dei problemi nell'uso delle API che l'accesso locale evita.

What motivates people to desire local read-only access?

Ottimizzazione API:

LinkedIn ha un'interessante presentazione (dal 2009) sulla questione dell'ottimizzazione della loro API e del perché è importante per loro su vasta scala. http://www.slideshare.net/linkedin/building-consistent-restful-apis-in-a-highperformance-environment

In breve, una volta che un'API deve supportare molti casi d'uso diversi, può facilmente entrare nella situazione in cui supporta un caso d'uso in modo ottimale e il resto piuttosto male dal punto di vista della rete e del database.

Se l'API non ha la stessa raffinatezza di LinkedIn, puoi facilmente ottenere gli scenari in cui:

  • L'API recupera molti più dati del necessario (sprechi)
  • API Chatty dove devi chiamare l'API più volte

Sì, possiamo ovviamente aggiungere la memorizzazione nella cache alle API, ma alla fine la chiamata API è una chiamata remota e ci sono una serie di ottimizzazioni disponibili per gli sviluppatori quando i dati sono locali.

Ho il sospetto che ci sia un gruppo di persone là fuori che potrebbero aggiungerlo come:

  • Replica a basso costo dei dati anagrafici nel database dei microservizi (senza costi di sviluppo e tecnicamente efficiente)
  • Fede nella normalizzazione e la resilienza delle applicazioni ai cambiamenti dello schema
  • Capacità di ottimizzare facilmente ogni caso d'uso ed evitare potenzialmente chiamate API remote loquaci / dispendiose / inefficienti
  • Oltre ad alcuni altri vantaggi in termini di vincoli e design coerente

Questa risposta è troppo lunga. Scuse!!


L'aggiunta di una colonna generalmente interrompe le applicazioni. Se si dispone di "stipendio", l'applicazione che somma tutti gli stipendi si interrompe quando viene introdotta una nuova colonna "salary_currency".
Kubanczyk,

Veramente? Dipende dalla tua definizione di "interruzioni" suppongo. Se l'app fosse in produzione e funzionasse come previsto senza "salary_currency", perché dovresti considerare l'applicazione ora interrotta?
Rob Bygrave,

L'applicazione funziona senza errori e visualizza alcuni numeri. Ma è inutile. Quando il CEO vedrà che la somma degli stipendi dell'ultimo mese è di 6 milioni invece di 50 mila (a causa di un nuovo dipendente che viene pagato in Won sudcoreani) la definizione di produzione utile / inutile non verrà discussa molto.
Kubanczyk,

0

La gestione dello stato (potenzialmente un database) può essere distribuita nel contenitore di Microservice ed esposta tramite un'API. Il database di un Microservice non è visibile ad altri sistemi esterni al contenitore, ma solo all'API. In alternativa, è possibile che un altro servizio (ad esempio una cache) gestisca lo stato tramite un'API. Avere tutte le dipendenze di Microservice (diverse dalle chiamate API ad altri servizi) all'interno di un singolo contenitore distribuibile è una distinzione chiave nell'architettura. Se uno non lo capisce, torna indietro e studia l'architettura.

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.