I microservizi sono uno stile di architettura diffuso per la creazione di applicazioni che offrono resilienza, scalabilità elevata, possibilità di distribuzione indipendente e capacità di evolversi rapidamente. Ma un'architettura di microservizi efficiente richiede un approccio diverso alla progettazione e allo sviluppo di applicazioni.
Un'architettura di microservizi è costituita da un insieme di servizi ridotti autonomi. Ogni servizio è indipendente e deve implementare una singola funzionalità aziendale all'interno di un contesto delimitato. Un contesto delimitato è una divisione naturale all'interno di un'azienda e fornisce un limite esplicito all'interno del quale esiste un modello di dominio.
Cosa sono i microservizi?
I microservizi sono ridotti, indipendenti e a regime di controllo libero. Le dimensioni sono tali da consentirne la scrittura e la gestione da parte di un unico piccolo team di sviluppatori.
Ogni servizio è una base di codici distinta, che può essere gestita da un team di sviluppo di piccole dimensioni.
I servizi possono essere distribuiti in modo indipendente. Un team può aggiornare un servizio esistente senza ricompilare e ridistribuire l'intera applicazione.
I servizi sono responsabili della persistenza dei propri dati o dello stato esterno. Questo comportamento differisce dal modello tradizionale, in cui la persistenza dei dati viene gestita da un livello dati distinto.
I servizi comunicano tra loro tramite API ben definite. I dettagli di implementazione interna di ogni servizio sono nascosti da altri servizi.
Supporta la programmazione poliglotta. Ad esempio, i servizi non devono condividere lo stesso stack di tecnologie, librerie o framework.
Oltre ai servizi, in un'architettura di microservizi tipica compaiono alcuni altri componenti:
Gestione/orchestrazione. Questo componente è responsabile del posizionamento dei servizi sui nodi, dell'identificazione degli errori, del ribilanciamento dei servizi tra i nodi e così via. In genere, questo componente è una tecnologia in serie, ad esempio Kubernetes, invece di essere creata in modo personalizzato.
API Gateway. Il gateway API è il punto di ingresso per i client. Invece di chiamare direttamente i servizi, i client chiamano il gateway API, che inoltra la chiamata ai servizi appropriati sul back-end.
I vantaggi associati all'uso di un gateway API includono:
Separa i client dai servizi, di cui può essere effettuato il refactoring o il controllo delle versioni senza la necessità di aggiornare tutti i client.
I servizi possono usare protocolli di messaggistica non compatibili con il Web, come AMQP.
Il gateway API può eseguire altre funzioni trasversali, come l'autenticazione, la registrazione, la terminazione SSL e il bilanciamento del carico.
Criteri predefiniti, ad esempio per la limitazione, la memorizzazione nella cache, la trasformazione o la convalida.
Vantaggi
Agilità. Poiché i microservizi vengono distribuiti in modo indipendente, è più facile gestire le correzioni di bug e i rilasci delle funzionalità. È possibile aggiornare un servizio senza ridistribuire l'intera applicazione ed eseguire il rollback di un aggiornamento in caso di errore. In molte applicazioni tradizionali un bug rilevato in una parte dell'applicazione può bloccare l'intero processo di rilascio. Le nuove funzionalità potrebbero essere bloccate in attesa di una correzione di bug da integrare, testare e pubblicare.
Team dedicati di piccole dimensioni. Un microservizio deve essere sufficientemente piccolo da consentire a un singolo un team responsabile di una funzionalità di crearlo, testarlo e distribuirlo. I team di piccole dimensioni lavorano in modo più flessibile. I team di grandi dimensioni tendono a essere meno produttivi, perché la comunicazione è più lenta, la gestione è più complessa e la flessibilità diminuisce.
Codebase di dimensioni ridotte. In un'applicazione monolitica si verifica una tendenza nel tempo per cui le dipendenze del codice diventano tangente. L'aggiunta di una nuova funzionalità richiede il tocco del codice in molte posizioni. Un'architettura di microservizi non prevede la condivisione di codice o di archivi dati, quindi le dipendenze sono ridotte al minimo ed è più facile aggiungere nuove funzionalità.
Combinazione di tecnologie. I team possono scegliere la tecnologia più adatta al servizio, usando la combinazione di stack tecnologici più appropriata.
Isolamento degli errori. Se un singolo microservizio diventa non disponibile, non interromperà l'intera applicazione, purché i microservizi upstream siano progettati per gestire correttamente gli errori. Ad esempio, è possibile implementare il modello interruttore oppure progettare la soluzione in modo che i microservizi comunichino tra loro usando modelli di messaggistica asincroni.
Scalabilità. È quindi possibile ridimensionare i servizi e aumentare il numero di sottosistemi che richiedono più risorse, senza ampliare il livello di servizio dell'intera applicazione. Usando un agente di orchestrazione, ad esempio Kubernetes, è possibile comprimere una maggiore densità di servizi in un singolo host, che consente un utilizzo più efficiente delle risorse.
Isolamento dei dati. È molto più semplice eseguire aggiornamenti dello schema, perché è interessato solo un singolo microservizio. In un'applicazione monolitica, gli aggiornamenti dello schema possono diventare molto complessi, perché parti diverse dell'applicazione potrebbero toccare tutti gli stessi dati, apportando eventuali modifiche allo schema rischiose.
Problematiche
I vantaggi dei microservizi non sono esenti da problemi. Ecco alcuni degli aspetti da considerare prima di adottare un'architettura di microservizi.
Complessità. Un'applicazione di microservizi ha più parti mobili rispetto all'applicazione monolitica equivalente. Ogni servizio è più semplice, ma l'intero sistema nella sua totalità è più complesso.
Sviluppo e test. La scrittura di un servizio di piccole dimensioni che si basa su altri servizi dipendenti richiede un approccio diverso rispetto alla scrittura di una tradizionale applicazione monolitica o a più livelli. Gli strumenti esistenti non sempre sono progettati per gestire le dipendenze dei servizi. Effettuare il refactoring tra i limiti dei servizi può essere difficile. Può risultare complesso anche testare le dipendenze dei servizi, in particolare quando l'applicazione si evolve rapidamente.
Mancanza di governance. L'approccio decentralizzato alla creazione di microservizi presenta alcuni vantaggi, ma può anche causare problemi. Potrebbero esserci così tanti linguaggi e framework diversi che l'applicazione diventa difficile da gestire. Può essere utile applicare alcuni standard a livello di progetto, senza limitare eccessivamente la flessibilità dei team. Questo vale in special modo per le funzionalità trasversali come la registrazione.
Congestione e latenza di rete. L'uso di molti servizi granulari di dimensioni ridotte può comportare una maggiore comunicazione tra i servizi. Inoltre, se la catena delle dipendenze dei servizi diventa troppo lunga (il servizio A chiama il servizio B, che a sua volta chiama il servizio C...), l'ulteriore latenza può diventare un problema. Sarà necessario progettare le API con attenzione. Evitare API eccessivamente chatte, considerare i formati di serializzazione e cercare posizioni in cui usare modelli di comunicazione asincroni come il livellamento del carico basato su coda.
Integrità dei dati. Ogni microservizio è responsabile della persistenza dei propri dati. Di conseguenza, la coerenza dei dati tra più servizi può essere una sfida. Servizi diversi persistono i dati in momenti diversi, usando tecnologie diverse e con livelli di successo potenzialmente diversi. Quando più di un microservizio è coinvolto nella persistenza di una data nuova o modificata, è improbabile che la modifica completa dei dati possa essere considerata una transazione ACID. Al contrario, la tecnica è più allineata a BASE (Fondamentalmente disponibile, stato soft e infine coerente). Implementare la coerenza finale dove possibile.
Gestione. Per una corretta implementazione dei microservizi è necessaria una conoscenza avanzata dei concetti DevOps. La registrazione correlata tra i servizi può risultare complessa. In genere, la registrazione deve correlare più chiamate ai servizi per una singola operazione utente.
Controllo delle versioni. Gli aggiornamenti di un servizio non devono interrompere i servizi che dipendono da esso. Potrebbero venire aggiornati più servizi in un determinato momento, quindi senza un'attenta progettazione si potrebbero verificare problemi di compatibilità con le versioni precedenti o successive.
Competenze. I microservizi sono sistemi altamente distribuiti. Valutare attentamente se il team ha le competenze e l'esperienza necessarie.
Processo per la creazione di un'architettura di microservizi
Gli articoli elencati di seguito illustrano un approccio strutturale per la progettazione, la creazione e la gestione di un'architettura di microservizi.
Analisi del dominio. Per evitare le comuni insidie associate alla progettazione di microservizi, usare l'analisi del dominio per definirne i limiti. Seguire questa procedura:
- Usare l'analisi del dominio per modellare i microservizi.
- Usare la progettazione basata sul dominio tattica per progettare i microservizi.
- Identificare i limiti dei microservizi.
Progettare i servizi. I microservizi richiedono un approccio diverso alla progettazione e alla creazione di applicazioni. Per altre informazioni, vedere Progettazione di un'architettura di microservizi.
Gestire l'ambiente di produzione. Poiché le architetture di microservizi vengono distribuite, è necessario definire operazioni affidabili per la distribuzione e il monitoraggio.
- CI/CD per le architetture di microservizi
- Creare una pipeline CI/CD per i microservizi in Kubernetes
- Monitorare i microservizi in esecuzione nel servizio Azure Kubernetes