Considerazioni relative ai dati per i microservizi
Questo articolo descrive le considerazioni per la gestione dei dati in un'architettura di microservizi. Poiché ogni microservizio gestisce i propri dati, l'integrità dei dati e la coerenza dei dati sono problematiche critiche.
Un principio di base dei microservizi è che ogni servizio gestisce i propri dati. Due servizi non devono condividere un archivio dati. Ogni servizio è invece responsabile del proprio archivio dati privato, a cui gli altri servizi non possono accedere direttamente.
Il motivo di questa regola è evitare l'accoppiamento involontario tra i servizi, che può comportare se i servizi condividono gli stessi schemi di dati sottostanti. Se si verifica una modifica allo schema dei dati, la modifica deve essere coordinata in ogni servizio che si basa su tale database. Isolando l'archivio dati di ogni servizio, è possibile limitare l'ambito della modifica e mantenere l'agilità delle distribuzioni realmente indipendenti. Un altro motivo è che ogni microservizio può avere modelli di dati, query o modelli di lettura/scrittura specifici. L'uso di un archivio dati condiviso limita la capacità di ogni team di ottimizzare l'archiviazione dei dati per il servizio specifico.
Questo approccio porta naturalmente alla persistenza poliglotta , ovvero l'uso di più tecnologie di archiviazione dei dati all'interno di una singola applicazione. Un servizio potrebbe richiedere le funzionalità di lettura dello schema di un database di documenti. Un altro potrebbe richiedere l'integrità referenziale fornita da un sistema RDBMS. Ogni team è libero di fare la scelta migliore per il proprio servizio.
Nota
È consigliabile che i servizi convidano lo stesso server di database fisico. Il problema si verifica quando i servizi condividono lo stesso schema o leggono e scrivono nello stesso set di tabelle di database.
Sfide
Alcuni problemi derivano da questo approccio distribuito alla gestione dei dati. In primo luogo, potrebbe esserci ridondanza tra gli archivi dati, con lo stesso elemento di dati visualizzato in più posizioni. Ad esempio, i dati possono essere archiviati come parte di una transazione, quindi archiviati altrove per l'analisi, la creazione di report o l'archiviazione. I dati duplicati o partizionati possono causare problemi di integrità e coerenza dei dati. Quando le relazioni tra dati si estendono su più servizi, non è possibile usare tecniche di gestione dei dati tradizionali per applicare le relazioni.
La modellazione dei dati tradizionale usa la regola di "un fatto in un'unica posizione". Ogni entità viene visualizzata esattamente una volta nello schema. Altre entità possono contenere riferimenti, ma non duplicati. Il vantaggio ovvio dell'approccio tradizionale è che gli aggiornamenti vengono eseguiti in un'unica posizione, evitando problemi con la coerenza dei dati. In un'architettura di microservizi è necessario considerare il modo in cui gli aggiornamenti vengono propagati tra i servizi e come gestire la coerenza finale quando i dati vengono visualizzati in più posizioni senza coerenza assoluta.
Approcci alla gestione dei dati
Non esiste un unico approccio corretto in tutti i casi, ma di seguito sono riportate alcune linee guida generali per la gestione dei dati in un'architettura di microservizi.
Definire il livello di coerenza richiesto per ogni componente, preferendo la coerenza finale laddove possibile. Comprendere le posizioni del sistema in cui è necessaria una coerenza assoluta o transazioni ACID e le posizioni in cui la coerenza finale è accettabile. Per altre indicazioni sui componenti, vedere Uso di DDD tattico per progettare microservizi .
Quando sono necessarie garanzie di coerenza assoluta, un servizio può rappresentare l'origine della verità per una determinata entità, esposta tramite un'API. Altri servizi possono contenere la propria copia dei dati o un subset dei dati, che alla fine sono coerenti con i dati master, ma non considerati l'origine della verità. Si supponga, ad esempio, che un sistema di e-commerce con un servizio ordini cliente e un servizio di raccomandazione. Il servizio di raccomandazione potrebbe restare in ascolto degli eventi del servizio ordini, ma se un cliente richiede un rimborso, si tratta del servizio ordini, non del servizio di raccomandazione, con la cronologia delle transazioni completa.
Per le transazioni, usare modelli come Supervisore agente dell'utilità di pianificazione e Transazione di compensazione per mantenere i dati coerenti tra diversi servizi. Potrebbe essere necessario archiviare una parte aggiuntiva di dati che acquisisce lo stato di un'unità di lavoro che si estende su più servizi, per evitare errori parziali tra più servizi. Ad esempio, mantenere un elemento di lavoro in una coda durevole mentre è in corso una transazione in più passaggi.
Archiviare solo i dati necessari per un servizio. Un servizio potrebbe richiedere solo un subset di informazioni su un'entità di dominio. Ad esempio, nel contesto con limiti di spedizione, è necessario sapere quale cliente è associato a una determinata consegna. Non è tuttavia necessario l'indirizzo di fatturazione del cliente, gestito dal contesto delimitato account. Considerare attentamente il dominio e usare un approccio DDD può essere utile qui.
Valutare se i servizi sono coerenti e ad accoppiamento libero. Se due servizi scambiano continuamente informazioni tra loro, con conseguente chatty API, potrebbe essere necessario ridisegnare i limiti del servizio, unendo due servizi o refactoring delle relative funzionalità.
Usa uno stile di architettura basato su eventi. In questo stile di architettura, un servizio pubblica un evento quando vengono apportate modifiche ai modelli o alle entità pubbliche. I servizi interessati possono sottoscrivere questi eventi. Ad esempio, un altro servizio potrebbe usare gli eventi per costruire una vista materializzata dei dati più adatti per l'esecuzione di query.
Un servizio proprietario di eventi deve pubblicare uno schema che può essere usato per automatizzare la serializzazione e deserializzazione degli eventi, per evitare un accoppiamento stretto tra server di pubblicazione e sottoscrittori. Si consideri uno schema JSON o un framework come Microsoft Bond, Protobuf o Avro.
Su larga scala, gli eventi possono diventare un collo di bottiglia nel sistema, quindi è consigliabile usare l'aggregazione o l'invio in batch per ridurre il carico totale.
Esempio: scelta di archivi dati per l'applicazione di recapito tramite drone
Gli articoli precedenti di questa serie illustrano un servizio di consegna tramite drone come esempio in esecuzione. Per altre informazioni sullo scenario e sull'implementazione di riferimento corrispondente , vedere qui. Questo esempio è ideale per le industrie aeree e aerospaziali.
Per riepilogare, questa applicazione definisce diversi microservizi per la pianificazione delle consegne tramite drone. Quando un utente pianifica un nuovo recapito, la richiesta client include informazioni sulla consegna, ad esempio posizioni di ritiro e rilascio, e sul pacchetto, ad esempio dimensioni e peso. Queste informazioni definiscono un'unità di lavoro.
I vari servizi back-end si occupano di parti diverse delle informazioni nella richiesta e hanno anche profili di lettura e scrittura diversi.
Servizio di recapito
Il servizio di recapito archivia le informazioni relative a ogni recapito attualmente pianificato o in corso. Ascolta gli eventi dei droni e tiene traccia dello stato delle consegne in corso. Invia anche gli eventi di dominio con gli aggiornamenti dello stato del recapito.
È previsto che gli utenti controllino spesso lo stato di un recapito mentre sono in attesa del pacchetto. Di conseguenza, il servizio di recapito richiede un archivio dati che enfatizza la velocità effettiva (lettura e scrittura) nell'archiviazione a lungo termine. Inoltre, il servizio di recapito non esegue query o analisi complesse, recupera semplicemente lo stato più recente per un determinato recapito. Il team del servizio di distribuzione ha scelto Cache Redis di Azure per ottenere prestazioni di lettura/scrittura elevate. Le informazioni archiviate in Redis sono relativamente brevi. Una volta completato il recapito, il servizio Cronologia recapito è il sistema di record.
Servizio Cronologia recapito
Il servizio Cronologia recapito è in ascolto degli eventi di stato del recapito dal servizio di recapito. Archivia questi dati nell'archiviazione a lungo termine. Esistono due casi d'uso diversi per questi dati cronologici, che hanno requisiti di archiviazione dei dati diversi.
Il primo scenario consiste nell'aggregare i dati ai fini dell'analisi dei dati per ottimizzare l'azienda o migliorare la qualità del servizio. Si noti che il servizio Cronologia recapito non esegue l'analisi effettiva dei dati. È responsabile solo dell'inserimento e dell'archiviazione. Per questo scenario, l'archiviazione deve essere ottimizzata per l'analisi dei dati su un set di dati di grandi dimensioni, usando un approccio basato su schema in lettura per supportare un'ampia gamma di origini dati. Azure Data Lake Store è ideale per questo scenario. Data Lake Store è un file system Apache Hadoop compatibile con Hadoop Distributed File System (HDFS) ed è ottimizzato per le prestazioni per gli scenari di analisi dei dati.
L'altro scenario consente agli utenti di cercare la cronologia di un recapito al termine del recapito. Azure Data Lake non è ottimizzato per questo scenario. Per ottenere prestazioni ottimali, Microsoft consiglia di archiviare i dati delle serie temporali in Data Lake in cartelle partizionate per data. Vedere Ottimizzazione di Azure Data Lake Store per le prestazioni. Tuttavia, tale struttura non è ottimale per cercare singoli record in base all'ID. A meno che non si conosca anche il timestamp, una ricerca per ID richiede l'analisi dell'intera raccolta. Di conseguenza, il servizio Cronologia recapito archivia anche un subset dei dati cronologici in Azure Cosmos DB per una ricerca più rapida. I record non devono rimanere in Azure Cosmos DB per un periodo illimitato. Le consegne meno recenti possono essere archiviate, ad esempio dopo un mese. Questa operazione può essere eseguita eseguendo un processo batch occasionale. L'archiviazione dei dati meno recenti può ridurre i costi per Cosmos DB mantenendo comunque i dati disponibili per la creazione di report cronologici da Data Lake.
Servizio pacchetto
Il servizio Pacchetto archivia informazioni su tutti i pacchetti. I requisiti di archiviazione per il pacchetto sono:
- Archiviazione a lungo termine.
- In grado di gestire un volume elevato di pacchetti, che richiede una velocità effettiva di scrittura elevata.
- Supportare query semplici in base all'ID pacchetto. Nessun join complesso o requisiti per l'integrità referenziale.
Poiché i dati del pacchetto non sono relazionali, è appropriato un database orientato ai documenti e Azure Cosmos DB può ottenere una velocità effettiva elevata usando raccolte partizionate. Il team che lavora nel servizio pacchetto ha familiarità con lo stack MEAN (MongoDB, Express.js, AngularJS e Node.js), in modo da selezionare l'API MongoDB per Azure Cosmos DB. Ciò consente loro di sfruttare l'esperienza esistente con MongoDB, ottenendo al tempo stesso i vantaggi di Azure Cosmos DB, che è un servizio di Azure gestito.
Passaggi successivi
Informazioni sui modelli di progettazione che consentono di attenuare alcune problematiche comuni in un'architettura di microservizi.