Introduzione ai microservizi

Last reviewed 2021-06-24 UTC

Questa guida di riferimento è la prima di una serie in quattro parti sulla progettazione, la creazione e il deployment di microservizi. Questa serie descrive i vari elementi di un'architettura basata su microservizi. La serie include informazioni sui vantaggi e sugli svantaggi del pattern dell'architettura dei microservizi e su come applicarlo.

  1. Introduzione ai microservizi (questo documento)
  2. Refactoring di un monolite in microservizi
  3. Comunicazione tra servizi in una configurazione di microservizi
  4. Tracciamento distribuito in un'applicazione di microservizi

Questa serie è destinata agli sviluppatori di applicazioni e agli architetti che progettano e implementano la migrazione per il refactoring di un'applicazione monolitica in un'applicazione di microservizi.

Applicazioni monolitiche

Un'applicazione monolitica è un'applicazione software a un livello in cui moduli diversi vengono combinati in un unico programma. Ad esempio, se stai creando un'applicazione di e-commerce, l'applicazione dovrebbe avere un'architettura modulare allineata ai principi della programmazione orientata agli oggetti (OOP). Il seguente diagramma mostra un esempio di configurazione di un'applicazione di e-commerce, in cui l'applicazione è costituita da vari moduli. In un'applicazione monolitica, i moduli vengono definiti utilizzando una combinazione di costrutti del linguaggio di programmazione (come i pacchetti Java) e di artefatti di build (come i file JAR Java).

Un'applicazione monolitica utilizza diversi moduli.

Figura 1. Diagramma di un'applicazione di e-commerce monolitica con diversi moduli che utilizzano una combinazione di costrutti del linguaggio di programmazione.

Nella Figura 1, diversi moduli dell'applicazione di e-commerce corrispondono alla logica di business per il pagamento, la consegna e la gestione degli ordini. Tutti questi moduli vengono pacchettizzati e distribuiti come un singolo file eseguibile logico. Il formato effettivo dipende dal linguaggio e dal framework dell'applicazione. Ad esempio, molte applicazioni Java sono pacchettizzate come file JAR e ne viene eseguito il deployment su server delle applicazioni come Tomcat o Jetty. Analogamente, un'applicazione Rails o Node.js è pacchettizzata come gerarchia di directory.

Vantaggi del monolite

L'architettura monolitica è una soluzione convenzionale per la creazione di applicazioni. Di seguito sono riportati alcuni vantaggi dell'adozione di un design monolitico per la tua applicazione:

  • Puoi implementare test end-to-end di un'applicazione monolitica utilizzando strumenti come Selenium.
  • Per eseguire il deployment di un'applicazione monolitica, puoi semplicemente copiare l'applicazione in pacchetto su un server.
  • Tutti i moduli di un'applicazione monolitica condividono memoria, spazio e risorse, pertanto puoi utilizzare un'unica soluzione per risolvere problemi trasversali come logging, memorizzazione nella cache e sicurezza.
  • L'approccio monolitico può offrire vantaggi in termini di prestazioni, perché i moduli possono chiamarsi direttamente. Al contrario, i microservizi richiedono in genere una chiamata di rete per comunicare tra loro.

Sfide monolitiche

Spesso i monoliti complessi diventano progressivamente più difficili da creare, sottoporre a debug e ragionare. A un certo punto, i problemi superano i vantaggi.

  • In genere le applicazioni crescono nel tempo. Può diventare complicato implementare le modifiche in un'applicazione complessa e di grandi dimensioni con moduli strettamente accoppiati. Poiché ogni modifica al codice influisce sull'intero sistema, devi coordinare accuratamente le modifiche. Il coordinamento delle modifiche allunga molto il processo complessivo di sviluppo e test rispetto alle applicazioni basate su microservizi.
  • Può essere complicato ottenere integrazione e deployment continui (CI/CD) con un monolite di grandi dimensioni. Questa complessità è dovuta al fatto che è necessario eseguire nuovamente il deployment dell'intera applicazione per aggiornarne una qualsiasi parte. Inoltre, è probabile che tu debba eseguire test manuali approfonditi dell'intera applicazione per verificare la presenza di regressioni.
  • La scalabilità delle applicazioni monolitiche può essere difficile quando moduli diversi hanno requisiti in termini di risorse contrastanti. Ad esempio, un modulo potrebbe implementare una logica di elaborazione delle immagini che utilizza molta CPU. Un altro modulo potrebbe essere un database in memoria. Poiché questi moduli vengono distribuiti insieme, è necessario scendere a compromessi sulla scelta dell'hardware.
  • Poiché tutti i moduli vengono eseguiti nello stesso processo, un bug in qualsiasi modulo, ad esempio una perdita di memoria, può causare l'arresto dell'intero sistema.
  • Le applicazioni monolitiche aggiungono complessità quando vuoi adottare nuovi framework e linguaggi. Ad esempio, è costoso (in termini di tempo e denaro) riscrivere un'intera applicazione per utilizzare un nuovo framework, anche se questo è notevolmente migliore.

Applicazioni basate su microservizi

Un microservizio in genere implementa un insieme di caratteristiche o funzionalità distinte. Ogni microservizio è una mini applicazione che ha la propria architettura e logica di business. Ad esempio, alcuni microservizi espongono un'API utilizzata da altri microservizi o dai client dell'applicazione, come integrazioni di terze parti con gateway di pagamento e logistica.

La Figura 1 mostra un'applicazione di e-commerce monolitica con diversi moduli. Il seguente diagramma mostra una possibile scomposizione dell'applicazione di e-commerce in microservizi:

Un'applicazione monolitica viene scomposta in microservizi.

Figura 2. Diagramma di un'applicazione di e-commerce con aree funzionali implementate da microservizi.

Nella Figura 2, un microserve dedicato implementa ogni area funzionale dell'applicazione di e-commerce. Ogni servizio di backend potrebbe esporre un'API e i servizi consumano le API fornite da altri servizi. Ad esempio, per visualizzare le pagine web, i servizi UI richiamano il servizio di pagamento e altri servizi. I servizi possono anche utilizzare una comunicazione asincrona, basata su messaggi. Per ulteriori informazioni su come i servizi comunicano tra loro, consulta il terzo documento di questa serie, Comunicazione tra servizi in una configurazione di microservizi.

Il pattern di architettura dei microservizi cambia in modo significativo la relazione tra l'applicazione e il database. Invece di condividere un singolo database con altri servizi, consigliamo che ogni servizio abbia il proprio database che meglio si adatta ai propri requisiti. Quando hai un database per ogni servizio, ti assicuri il basso accoppiamento tra i servizi perché tutte le richieste di dati passano attraverso l'API del servizio e non direttamente attraverso il database condiviso. Il seguente schema mostra un pattern di architettura dei microservizi in cui ogni servizio ha il proprio database:

Ogni microservizio ha il proprio database.

Figura 3. Ogni servizio in un'architettura di microservizi ha il proprio database.

Nella figura 3, il servizio degli ordini nell'applicazione di e-commerce funziona bene utilizzando un database orientato ai documenti con funzionalità di ricerca in tempo reale. I servizi di pagamento e distribuzione si basano sull'atomicità, la coerenza, l'isolamento, la durabilità (ACID) garantite da un database relazionale.

Vantaggi dei microservizi

Il pattern di architettura dei microservizi affronta il problema della complessità descritto nella precedente sezione Sfide di Monolith. Un'architettura di microservizi offre i seguenti vantaggi:

  • Anche se la funzionalità totale è rimasta invariata, puoi utilizzare i microservizi per separare l'applicazione in blocchi o servizi gestibili. Ogni servizio ha un confine ben definito sotto forma di RPC o API basata su messaggi. Pertanto, i singoli servizi possono essere più veloci da sviluppare e più facili da comprendere e gestire.
  • I team autonomi possono sviluppare in modo indipendente i singoli servizi. Puoi organizzare i microservizi in base ai confini aziendali, non in base alle capacità tecniche di un prodotto. I team vengono organizzati secondo un'unica responsabilità indipendente per l'intero ciclo di vita del software assegnato, dallo sviluppo al test, fino al deployment, fino alla manutenzione e al monitoraggio.
  • Il processo di sviluppo indipendente di microservizi consente inoltre agli sviluppatori di scrivere ogni microservizio in un linguaggio di programmazione diverso, creando un'applicazione poliglotta. Se utilizzi il linguaggio più efficace per ogni microservizio, puoi sviluppare un'applicazione più rapidamente e ottimizzarla per ridurre la complessità del codice e aumentare le prestazioni e la funzionalità.
  • Se disaccoppi le funzionalità da un monolite, puoi fare in modo che i team indipendenti rilascino il microservizio in modo indipendente. I cicli di rilascio indipendenti possono aiutare a migliorare la velocità dei tuoi team e il time to market del prodotto.
  • L'architettura basata su microservizi consente inoltre di scalare ciascun servizio in modo indipendente. Puoi eseguire il deployment del numero di istanze di ciascun servizio che soddisfano i suoi vincoli di capacità e disponibilità. Puoi anche utilizzare l'hardware che meglio corrisponde ai requisiti delle risorse di un servizio. Scalando i servizi in modo indipendente, contribuisci ad aumentare la disponibilità e l'affidabilità dell'intero sistema.

Di seguito sono riportate alcune istanze specifiche in cui può essere utile eseguire la migrazione da un monolite a un'architettura basata su microservizi:

  • Implementazione di miglioramenti in termini di scalabilità, gestibilità, agilità o velocità di distribuzione.
  • Riscrittura incrementale di un'applicazione legacy di grandi dimensioni in uno stack tecnologico e linguistico moderno per soddisfare le nuove esigenze aziendali.
  • Estrazione di applicazioni aziendali o servizi trasversali per poterli riutilizzare in più canali. Alcuni esempi di servizi che potresti voler riutilizzare sono servizi di pagamento, servizi di accesso, servizi di crittografia, servizi di ricerca voli, servizi di profili clienti e servizi di notifica.
  • L'adozione di un linguaggio o framework appositamente progettati per una funzionalità specifica di un monolite esistente.

Sfide dei microservizi

I microservizi presentano alcune sfide rispetto ai monoliti, tra cui:

  • Una delle principali sfide dei microservizi è la complessità derivante dal fatto che l'applicazione è un sistema distribuito. Gli sviluppatori devono scegliere e implementare un meccanismo di comunicazione tra i servizi. I servizi devono anche gestire gli errori parziali e la mancata disponibilità dei servizi upstream.
  • Un'altra sfida relativa ai microservizi è che devi gestire le transazioni tra vari microservizi (note anche come transazione distribuita). Le operazioni aziendali che aggiornano più entità aziendali sono abbastanza comuni e di solito vengono applicate in un modo atomico, in cui vengono applicate tutte le operazioni o tutto non funziona. L'aggregazione di più operazioni in una singola transazione del database garantisce l'atomicità.

    In un'applicazione basata su microservizi, le operazioni aziendali possono essere distribuite su diversi microservizi, quindi è necessario aggiornare più database di proprietà dei diversi servizi. In caso di errore, non è banale monitorare l'errore o il successo delle chiamate ai diversi microservizi ed eseguire il rollback dello stato. Lo scenario peggiore può comportare dati incoerenti tra i servizi quando il rollback dello stato a causa di errori non è avvenuto correttamente. Per informazioni sulle varie metodologie per configurare transazioni distribuite tra i servizi, consulta il terzo documento di questa serie, Comunicazione tra servizi in una configurazione di microservizi.

  • I test completi delle applicazioni basate su microservizi sono più complessi rispetto a quelli di un'applicazione monolitica. Ad esempio, per testare la funzionalità di elaborazione di un ordine in un servizio di e-commerce monolitico, devi selezionare gli articoli, aggiungerli a un carrello ed effettuare il pagamento. Per testare lo stesso flusso in un'architettura basata su microservizi, più servizi, ad esempio frontend, ordine e pagamento, si chiamano a vicenda per completare l'esecuzione del test.

  • Il deployment di un'applicazione basata su microservizi è più complesso rispetto al deployment di un'applicazione monolitica. Un'applicazione di microservizi è costituita in genere da molti servizi, ognuno dei quali ha più istanze di runtime. Devi inoltre implementare un meccanismo di Service Discovery che consenta a un servizio di rilevare le località di eventuali altri servizi con cui deve comunicare.

  • Un'architettura di microservizi aggiunge overhead alle operazioni perché ci sono più servizi da monitorare e per cui generare avvisi. L'architettura basata su microservizi presenta anche più punti di errore a causa dell'aumento delle comunicazioni point-to-service. È possibile eseguire il deployment di un'applicazione monolitica in un piccolo cluster di server applicazioni. Un'applicazione basata su microservizi può avere decine di servizi distinti per la creazione, il test, il deployment e l'esecuzione, potenzialmente in più linguaggi e ambienti. Tutti questi servizi devono essere in cluster per il failover e la resilienza. La produzione di un'applicazione di microservizi richiede un'infrastruttura operativa e di monitoraggio di alta qualità.

  • La divisione dei servizi in un'architettura basata su microservizi consente all'applicazione di eseguire più funzioni contemporaneamente. Tuttavia, poiché i moduli vengono eseguiti come servizi isolati, la latenza viene introdotta nei tempi di risposta dovuti alle chiamate di rete tra i servizi.

  • Non tutte le applicazioni sono abbastanza grandi da essere suddivise in microservizi. Inoltre, alcune applicazioni richiedono una stretta integrazione tra i componenti, ad esempio applicazioni che devono elaborare flussi rapidi di dati in tempo reale. Eventuali livelli di comunicazione aggiuntivi tra i servizi potrebbero rallentare l'elaborazione in tempo reale. Pensare in anticipo alla comunicazione tra i servizi può fornire insight utili per contrassegnare chiaramente i confini dei servizi.

Quando decidi se l'architettura di microservizi è la migliore per la tua applicazione, considera i seguenti punti:

  • Le best practice per i microservizi richiedono database per servizio. Quando esegui la modellazione dei dati per la tua applicazione, valuta se i database per servizio sono adatti alla tua applicazione.
  • Quando implementi un'architettura di microservizi, devi instrumentare e monitorare l'ambiente in modo da poter identificare i colli di bottiglia, rilevare e prevenire errori e supportare la diagnostica.
  • In un'architettura basata su microservizi, ogni servizio ha controlli di accesso separati. Per garantire la sicurezza, devi proteggere l'accesso a ciascun servizio sia all'interno dell'ambiente sia da applicazioni esterne che utilizzano le relative API.
  • La comunicazione sincrona tra servizi riduce in genere la disponibilità di un'applicazione. Ad esempio, se il servizio degli ordini in un'applicazione di e-commerce richiama in modo sincrono altri servizi upstream e se tali servizi non sono disponibili, non può creare un ordine. Pertanto, ti consigliamo di implementare una comunicazione asincrona e basata su messaggi.

Quando eseguire la migrazione di un'applicazione monolitica ai microservizi

Se stai già eseguendo con successo un monolite, l'adozione di microservizi è un costo di investimento significativo per il tuo team. Team diversi implementano i principi dei microservizi in modi diversi. Ogni team di tecnici ha risultati unici in base alla dimensione o al numero di microservizi necessari.

Per determinare se i microservizi sono l'approccio migliore per la tua applicazione, identifica innanzitutto gli obiettivi aziendali o i punti deboli chiave che vuoi risolvere. Potrebbero esserci modi più semplici per raggiungere i tuoi obiettivi o risolvere i problemi che identifichi. Ad esempio, se vuoi fare lo scale up più rapidamente della tua applicazione, potresti scoprire che la scalabilità automatica è una soluzione più efficiente. Se rilevi bug in produzione, puoi iniziare implementando i test delle unità e l'integrazione continua (CI).

Se ritieni che un approccio basato su microservizi sia il modo migliore per raggiungere i tuoi obiettivi, inizia estraendo un servizio dal monolite e sviluppalo, testalo ed eseguine il deployment in produzione. Per ulteriori informazioni, consulta il prossimo documento di questa serie, Refactoring di un monolite in microservizi. Dopo aver estratto correttamente un servizio e averlo eseguito in produzione, avvia l'estrazione del servizio successivo e continua ad apprendere da ogni ciclo.

Il pattern di architettura di microservizi scompone un sistema in un insieme di servizi di cui è possibile eseguire il deployment in modo indipendente. Quando sviluppi un'applicazione monolitica, devi coordinare team di grandi dimensioni, il che può causare un rallentamento dello sviluppo del software. Quando implementi un'architettura di microservizi, consenti a piccoli team autonomi di lavorare in parallelo, il che può accelerare il tuo sviluppo.

Nel prossimo documento di questa serie, Refactoring di un monolite in microservizi, scoprirai varie strategie per il refactoring di un'applicazione monolitica in microservizi.

Passaggi successivi