Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
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. La creazione di un'architettura di microservizi di successo richiede un cambiamento fondamentale nella mentalità. Va oltre la scomposizione di un'applicazione in servizi più piccoli. È anche necessario ripensare il modo in cui i sistemi vengono progettati, distribuiti e gestiti.
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 componenti di piccole dimensioni, indipendenti e ad accoppiamento libero che un singolo piccolo team di sviluppatori può scrivere e gestire. Ogni servizio viene gestito come codebase separato, che consente a un piccolo team di gestirlo in modo efficiente. Poiché i servizi possono essere distribuiti in modo indipendente, i team possono aggiornare i servizi esistenti senza ricompilare o ridistribuire l'intera applicazione. A differenza dei modelli tradizionali con un livello dati centralizzato, i microservizi sono responsabili della persistenza dei propri dati o dello stato esterno. Comunicano tramite API ben definite, che mantiene le implementazioni interne nascoste da altri servizi. Questa architettura supporta anche la programmazione poliglotta, il che significa che i servizi non devono condividere lo stesso stack di tecnologie, librerie o framework.
Componenti
Oltre ai servizi stessi, altri componenti vengono visualizzati in una tipica architettura di microservizi:
Gestione o orchestrazione: Questo componente di gestione gestisce l'orchestrazione dei microservizi. Pianifica e distribuisce i servizi tra i nodi, rileva gli errori, esegue il ripristino da errori e abilita la scalabilità automatica in base alla richiesta. Una piattaforma di orchestrazione dei contenitori come Kubernetes offre in genere questa funzionalità. Negli ambienti nativi del cloud, soluzioni come App Contenitore di Azure offrono orchestrazione gestita e scalabilità predefinita. Questi strumenti riducono la complessità della distribuzione e il sovraccarico operativo.
Gateway API: Il gateway API funge da punto di ingresso per i client. I client inviano richieste al gateway API anziché chiamare direttamente i servizi. Il gateway inoltra tali richieste ai servizi back-end appropriati. Gestisce anche problemi trasversali, ad esempio l'autenticazione, la registrazione e il bilanciamento del carico. Nelle architetture di microservizi nativi del cloud, proxy di servizi leggeri come Envoy e Nginx supportano la comunicazione interna da servizio a servizio. Questo tipo di traffico interno, noto come traffico est-ovest, consente il routing avanzato e il controllo del traffico.
Middleware orientato ai messaggi: Le piattaforme di messaggistica come Apache Kafka e il bus di servizio di Azure consentono la comunicazione asincrona nei microservizi promuovendo l'accoppiamento libero e supportando la scalabilità elevata. Costituiscono la base delle architetture guidate dagli eventi. Questo approccio consente ai servizi di reagire agli eventi in tempo reale e di comunicare tramite la messaggistica asincrona.
Osservabilità: Una strategia di osservabilità efficace consente ai team di mantenere l'affidabilità del sistema e risolvere rapidamente i problemi. La registrazione centralizzata riunisce i log per supportare la diagnostica più semplice. Il monitoraggio in tempo reale con agenti e framework di monitoraggio delle prestazioni delle applicazioni come OpenTelemetry offre visibilità sull'integrità e sulle prestazioni del sistema. La traccia distribuita tiene traccia delle richieste oltre i limiti del servizio. Aiuta i team a trovare ostruzioni e migliorare le prestazioni.
Gestione dei dati: Un'architettura di database ben progettata supporta l'autonomia e la scalabilità. I microservizi usano spesso la persistenza poliglotta scegliendo tipi di database diversi, ad esempio SQL o NoSQL, in base alle esigenze specifiche di ogni servizio. Questo approccio è allineato alla progettazione basata su dominio (DDD) e all'idea del contesto delimitato. Ogni servizio è proprietario dei dati e dello schema. Questa proprietà riduce le dipendenze tra servizi e consente ai servizi di evolversi in modo indipendente. Questo modello decentralizzato migliora flessibilità, prestazioni e resilienza del sistema.
Vantaggi
Agilità: Poiché i microservizi vengono distribuiti in modo indipendente, è più facile gestire le correzioni di bug e le versioni 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, se si trova un bug in una parte dell'applicazione, può bloccare l'intero processo di rilascio. Ad esempio, un bug può bloccare le nuove funzionalità se è necessario integrare, testare e pubblicare una correzione di bug.
Team piccoli e focalizzati: Un microservizio deve essere abbastanza piccolo da poter essere costruito, testato e distribuito da un singolo team di funzionalità. 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, l'overhead di gestione aumenta e l'agilità diminuisce.
Codebase di piccole dimensioni: In un'applicazione monolitica, le dipendenze del codice spesso diventano ingarbugliate nel tempo. L'aggiunta di una nuova funzionalità potrebbe richiedere modifiche in molte parti della codebase. Un'architettura di microservizi evita questo problema non condividendo codice o archivi dati. Questo approccio riduce al minimo le dipendenze e semplifica l'introduzione di nuove funzionalità.
Combinazione di tecnologie: Teams può scegliere la tecnologia più adatta al proprio servizio usando una combinazione di stack tecnologici in base alle esigenze.
Isolamento degli errori: Se un singolo microservizio diventa non disponibile, non interrompe 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à: I servizi possono essere ridimensionati in modo indipendente. Questo approccio consente di espandere la capacità dei sottosistemi che richiedono più risorse senza espandere la capacità dell'intera applicazione. Usare un agente di orchestrazione, ad esempio Kubernetes, per aggiungere una maggiore densità di servizi a un singolo host, che consente un utilizzo più efficiente delle risorse.
Isolamento dei dati: L'aggiornamento di uno schema è più semplice in un'architettura di microservizi perché è interessato solo un microservizio. Al contrario, le applicazioni monolitiche possono complicare le modifiche dello schema, poiché più componenti interagiscono spesso con gli stessi dati. Questo accesso condiviso rende potenzialmente rischiose qualsiasi modifica.
Sfide
I vantaggi dei microservizi sono costituiti da compromessi. Prima di creare un'architettura di microservizi, considerare le sfide seguenti:
Complessità: Un'applicazione di microservizi ha più parti in movimento rispetto all'applicazione monolitica equivalente. Ogni servizio è più semplice, ma l'intero sistema nella sua totalità è più complesso. Quando si progetta l'applicazione, assicurarsi di considerare problemi come l'individuazione dei servizi, la coerenza dei dati, la gestione delle transazioni e la comunicazione tra servizi.
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 un'applicazione monolitica o a più livelli tradizionale. Gli strumenti esistenti non sono sempre progettati per funzionare con le dipendenze del servizio. Effettuare il refactoring tra i limiti dei servizi può essere difficile. È anche difficile testare le dipendenze del servizio, soprattutto quando l'applicazione si evolve rapidamente.
Mancanza di governance: L'approccio decentralizzato alla creazione di microservizi presenta 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 metodo si applica in particolare alle funzionalità trasversali, come la registrazione.
Congestione e latenza della rete: L'uso di molti servizi granulari di piccole dimensioni può comportare una maggiore comunicazione tra servizi. Inoltre, se la catena di dipendenze del servizio diventa troppo lunga (il servizio A chiama B, che a sua volta chiama C...), la latenza aggiuntiva può diventare un problema. È necessario progettare attentamente le API. Evitare API eccessivamente verbose, considerare i formati di serializzazione e cercare punti in cui utilizzare schemi di comunicazione asincrona, come il modello di livellamento del carico Queue-Based.
Integrità dei dati: Ogni microservizio è responsabile della persistenza dei 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 nel rendere persistenti i dati nuovi o modificati, è improbabile che la modifica completa dei dati possa essere considerata una transazione atomica, coerente, isolata e durevole (ACID). Al contrario, la tecnica è più allineata a Basically Available, Soft State, Eventual Consistency (BASE). Implementare la coerenza finale dove possibile.
Gestione: Un'architettura di microservizi di successo richiede una cultura DevOps matura. 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 a 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.
Set di competenze: I microservizi sono sistemi altamente distribuiti. Valutare attentamente se il team ha le competenze e l'esperienza necessarie.
Procedure consigliate
Modellare i servizi relativi al dominio aziendale. Usare DDD per identificare i contesti delimitati e definire limiti di servizio chiari. Evitare di creare servizi eccessivamente granulari, che possono aumentare la complessità e ridurre le prestazioni.
Decentralizzare tutto. I singoli team sono responsabili della progettazione e della creazione di servizi end-to-end. Evitare di condividere codice o schemi di dati.
Standardizzare le scelte tecnologiche limitando il numero di linguaggi e framework usati. Stabilire standard a livello di piattaforma per la registrazione, il monitoraggio e la distribuzione.
L'archiviazione dei dati deve essere privata per il servizio proprietario dei dati. Usare lo spazio di archiviazione migliore per ogni servizio e tipo di dati.
I servizi comunicano tramite API ben progettate. Evitare la perdita di dettagli di implementazione. Le API devono modellare il dominio, non l'implementazione interna del servizio.
Evitare l'accoppiamento tra i servizi. Le cause dell'accoppiamento includono schemi di database condivisi e protocolli di comunicazione rigidi.
Migliora la sicurezza utilizzando la Sicurezza del Livello di Trasporto (mTLS) reciproca per la crittografia tra servizi. Implementare il controllo degli accessi in base al ruolo e usare i gateway API per applicare i criteri.
Delega preoccupazioni trasversali, come l'autenticazione e la terminazione del Secure Sockets Layer, al gateway. Mesh di servizi e framework come Dapr possono anche aiutare a risolvere problemi comuni, ad esempio l'autenticazione mTLS e la resilienza.
Mantenere la conoscenza del dominio al di fuori del gateway. Il gateway deve gestire e instradare le richieste client senza alcuna conoscenza delle regole business o della logica di dominio. In caso contrario, il gateway diventa una dipendenza e può causare l'accoppiamento tra i servizi.
I servizi devono avere un accoppiamento libero e una coesione funzionale elevata. Le funzioni che probabilmente cambiano insieme devono essere raggruppate e distribuite insieme. Se risiedono in servizi separati, questi servizi finiscono per essere strettamente associati, perché una modifica in un servizio richiede l'aggiornamento dell'altro servizio. Una comunicazione eccessivamente verbosa tra due servizi potrebbe essere un sintomo di accoppiamento stretto e bassa coesione.
Usare pipeline di integrazione continua e distribuzione continua (CI/CD) per automatizzare i test e la distribuzione. Distribuire i servizi in modo indipendente e monitorare la salute del rollout.
Isolare gli errori. Usare strategie di resilienza per evitare errori all'interno di un servizio a catena. Per altre informazioni, vedere Modelli di resilienza e Progettare applicazioni affidabili.
Usare chaos engineering per testare la resilienza dell'architettura del microservizio e le relative dipendenze. Valutare e migliorare il modo in cui il sistema gestisce gli errori parziali.
Implementare la registrazione centralizzata, la traccia distribuita (OpenTelemetry) e la raccolta di metriche per garantire l'osservabilità.
Antipattern per i microservizi
Quando si progettano e implementano microservizi, spesso si verificano problemi specifici che possono compromettere i vantaggi di questo stile di architettura. Il riconoscimento di questi antipattern consente ai team di evitare costosi errori e di creare sistemi più resilienti e gestibili. Evitare gli antipattern seguenti:
L'implementazione di microservizi senza una conoscenza approfondita del dominio aziendale comporta limiti del servizio non allineati correttamente e compromette i vantaggi previsti.
La progettazione di eventi che dipendono da eventi passati o futuri viola il principio della messaggistica atomica e autonoma. Questa dipendenza impone ai consumer di attendere e ridurre l'affidabilità del sistema.
L'uso di entità di database come eventi espone i dettagli interni del servizio e spesso non riesce a comunicare la finalità aziendale corretta, che porta a integrazioni strettamente associate e poco chiare.
Evitare la duplicazione dei dati a tutti i costi è una pratica errata. L'uso di modelli come le viste materializzate per gestire copie locali migliora l'autonomia del servizio e riduce le dipendenze tra servizi.
L'uso di eventi generici forza i consumer a interpretare e filtrare i messaggi. Questo approccio aggiunge complessità non necessarie e riduce la chiarezza nelle comunicazioni guidate dagli eventi.
La condivisione di librerie o dipendenze comuni tra microservizi crea un accoppiamento stretto, che rende le modifiche rischiose e diffuse e va contro il principio dei servizi autonomi.
L'esposizione diretta dei microservizi ai consumer comporta un accoppiamento stretto, problemi di scalabilità e rischi per la sicurezza. L'uso di un gateway API fornisce un punto di ingresso pulito, gestibile e sicuro.
Mantenere i valori di configurazione all'interno dei microservizi strettamente associandoli agli ambienti specifici, rendendo più difficili le distribuzioni. Tuttavia, l'esternalizzazione della configurazione promuove flessibilità e portabilità dell'ambiente.
L'incorporamento della logica di sicurezza, ad esempio la convalida dei token direttamente all'interno di microservizi, complica il codice e la manutenzione. In alternativa, delegare la sicurezza a componenti dedicati mantiene i servizi concentrati e organizzati.
La mancata astrazione delle attività comuni dei microservizi risulta in codice ripetitivo soggetto a errori e riduce la flessibilità. In alternativa, l'uso di framework di astrazione come Dapr semplifica lo sviluppo separando la logica di business dalle problematiche dell'infrastruttura.
Creare un'architettura di microservizi
Gli articoli seguenti presentano un approccio strutturato per la progettazione, la compilazione e la gestione di un'architettura di microservizi.
Usare l'analisi del dominio: Per evitare problemi comuni durante la progettazione di microservizi, usare l'analisi del dominio per definire i limiti dei microservizi. Effettua i passaggi seguenti:
- 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 decentralizzato e agile alla progettazione e alla creazione di applicazioni. Per altre informazioni, vedere Progettare un'architettura di microservizi.
Operare nell'ambiente di produzione: Poiché le architetture di microservizi sono distribuite, è necessario disporre di operazioni affidabili per la distribuzione e il monitoraggio.