Introduzione ai microservizi

Last reviewed 2024-06-26 UTC

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

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

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

Applicazioni monolitiche

Un'applicazione monolitica è un'applicazione software a un livello in cui diversi moduli sono combinati in un unico programma. Ad esempio, se stai sviluppando un'applicazione di e-commerce, è previsto che abbia un'architettura modulare in linea con i 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 è composta 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 elementi 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, i 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 implementati come un singolo file eseguibile logico. Il formato effettivo dipende dal linguaggio e dal framework dell'applicazione. Ad esempio, molte applicazioni Java vengono pacchettizzate come file JAR e implementate su server di applicazioni come Tomcat o Jetty. Analogamente, un'applicazione Rails o Node.js viene pacchettizzata come una gerarchia di directory.

Vantaggi di Monolith

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 i 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 pacchettizzata su un server.
  • Tutti i moduli di un'applicazione monolitica condividono memoria, spazio e risorse, quindi puoi utilizzare una singola 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 tra loro. I microservizi, invece, in genere richiedono una chiamata di rete per comunicare tra loro.

Sfide del monolite

I monoliti complessi spesso diventano progressivamente più difficili da creare, eseguire il debug e comprendere. A un certo punto, i problemi superano i vantaggi.

  • In genere le applicazioni crescono nel tempo. Può diventare complicato implementare modifiche in un'applicazione grande e complessa con moduli fortemente accoppiati. Poiché qualsiasi modifica al codice interessa l'intero sistema, devi coordinare attentamente le modifiche. Il coordinamento delle modifiche rende il processo di sviluppo e test complessivo molto più lungo rispetto alle applicazioni di microservizi.
  • Può essere complicato realizzare l'integrazione e il deployment continui (CI/CD) con un monolite di grandi dimensioni. Questa complessità è dovuta al fatto che devi eseguire nuovamente il deployment dell'intera applicazione per aggiornarne una parte. Inoltre, è probabile che tu debba eseguire test manuali approfonditi dell'intera applicazione per verificare la presenza di regressioni.
  • Le applicazioni monolitiche possono essere difficili da scalare quando diversi moduli hanno requisiti di risorse in conflitto. Ad esempio, un modulo potrebbe implementare la logica di elaborazione delle immagini che richiede un'elevata potenza di calcolo della CPU. Un altro modulo potrebbe essere un database in memoria. Poiché questi moduli vengono implementati insieme, devi fare un compromesso sulla scelta dell'hardware.
  • Poiché tutti i moduli vengono eseguiti nello stesso processo, un bug in un qualsiasi modulo, come una perdita di memoria, può potenzialmente causare l'arresto dell'intero sistema.
  • Le applicazioni monolitiche aumentano la 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 funzionalità o caratteristiche distinte. Ogni microservizio è una mini-applicazione con la propria architettura e logica di business. Ad esempio, alcuni microservizi espongono un'API che viene utilizzata da altri microservizi o dai client dell'applicazione, come le 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 decomposizione 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 microservizio dedicato implementa ogni area funzionale dell'applicazione di e-commerce. Ogni servizio di backend potrebbe esporre un'API e i servizi consumeranno le API fornite da altri servizi. Ad esempio, per eseguire il rendering delle pagine web, i servizi UI invocano il servizio di pagamento e altri servizi. I servizi potrebbero anche utilizzare comunicazioni asincrone basate 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 modifica in modo significativo il rapporto tra l'applicazione e il database. Anziché condividere un unico database con altri servizi, consigliamo a ogni servizio di avere un proprio database che soddisfi al meglio i suoi requisiti. Quando hai un database per ogni servizio, assicuri un basso accoppiamento tra i servizi perché tutte le richieste di dati passano tramite l'API del servizio e non direttamente tramite il database condiviso. Il seguente diagramma mostra un pattern di architettura di microservizi in cui ogni servizio ha il suo 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 consegna si basano sulle forti garanzie di atomicità, coerenza, isolamento e durabilità (ACID) di un database relazionale.

Vantaggi dei microservizi

Il pattern di architettura di microservizi risolve il problema della complessità descritto nella precedente sezione Sfide del monolite. Un'architettura di microservizi offre i seguenti vantaggi:

  • Sebbene la funzionalità totale rimanga invariata, utilizzi i microservizi per dividere l'applicazione in blocchi o servizi gestibili. Ogni servizio ha un confine ben definito sotto forma di API RPC o basata su messaggi. Pertanto, i singoli servizi possono essere sviluppati più velocemente e sono più facili da capire e gestire.
  • I team autonomi possono sviluppare in modo indipendente singoli servizi. Puoi organizzare i microservizi in base ai confini aziendali, non alle funzionalità tecniche di un prodotto. Organizza i tuoi team in modo che abbiano una singola responsabilità indipendente per l'intero ciclo di vita del software assegnato, dallo sviluppo al test, dal deployment alla manutenzione e al monitoraggio.
  • Il processo di sviluppo dei microservizi indipendenti 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 le funzionalità.
  • Se scolleghi le funzionalità da un monolite, puoi consentire ai team indipendenti di rilasciare il proprio microservice in modo indipendente. I cicli di rilascio indipendenti possono contribuire a migliorare la velocità dei team e il tempo di lancio sul mercato dei prodotti.
  • L'architettura di microservizi ti consente inoltre di scalare ogni servizio in modo indipendente. Puoi eseguire il deployment del numero di istanze di ciascun servizio chesoddisfano i relativi vincoli di capacità e disponibilità. Puoi anche utilizzare l'hardware più adatto alle esigenze di risorse di un servizio. Quando scalate i servizi in modo indipendente, contribuiscete ad aumentare la disponibilità e l'affidabilità dell'intero sistema.

Di seguito sono riportati alcuni casi specifici in cui può essere utile eseguire la migrazione da un monolite a un'architettura di microservizi:

  • Implementazione di miglioramenti in termini di scalabilità, gestibilità, agilità o velocità di implementazione.
  • Riscrivere in modo incrementale una grande applicazione precedente in un linguaggio e uno stack tecnologico moderni per soddisfare le nuove esigenze aziendali.
  • Estrarre applicazioni aziendali o servizi trasversali in modo da poterli riutilizzare su più canali. Alcuni esempi di servizi che potresti voler riutilizzare sono servizi di pagamento, servizi di accesso, servizi di crittografia, servizi di ricerca di voli, servizi di profili dei clienti e servizi di notifica.
  • Adozione di un linguaggio o framework appositamente progettato 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à causata dal fatto che l'applicazione è un sistema distribuito. Gli sviluppatori devono scegliere e implementare un meccanismo di comunicazione tra servizi. I servizi devono anche gestire errori parziali e l'interruzione del servizio dei servizi a monte.
  • Un'altra sfida dei microservizi è che devi gestire le transazioni su diversi microservizi (chiamate anche transazioni distribuite). Le operazioni aziendali che aggiornano più entità aziendali sono abbastanza comuni e di solito vengono applicate in modo atomico, in cui vengono applicate tutte le operazioni o tutto non va a buon fine. Quando imbrigli più operazioni in una singola transazione di database, garantisci l'atomicità.

    In un'applicazione basata su microservizi, le operazioni aziendali potrebbero essere distribuite su diversi microservizi, quindi devi aggiornare più database di proprietà di servizi diversi. In caso di errore, non è banale monitorare l'esito positivo o negativo delle chiamate ai diversi microservizi e 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 le 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 ai test di un'applicazione monolitica. Ad esempio, per testare la funzionalità di elaborazione di un ordine in un servizio di e-commerce monolitico, seleziona gli articoli, aggiungili a un carrello e poi effettua il pagamento. Per testare lo stesso flusso in un'architettura basata su microservizi, più servizi, come frontend, ordine e pagamento, si richiamano 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 in genere è composta da molti servizi, ciascuno con più istanze di runtime. Devi anche implementare un meccanismo di Service Discovery che consenta a un servizio di rilevare le posizioni di tutti gli altri servizi con cui deve comunicare.

  • Un'architettura di microservizi aggiunge un overhead operativo perché ci sono più servizi da monitorare e per i quali generare avvisi. L'architettura di microservizi presenta inoltre più punti di errore a causa dell'aumento dei punti di comunicazione tra servizi. Un'applicazione monolitica potrebbe essere implementata in un piccolo cluster di server delle applicazioni. Un'applicazione basata su microservizi potrebbe avere decine di servizi separati da creare, testare, eseguire e distribuire, potenzialmente in più linguaggi ed ambienti. Tutti questi servizi devono essere raggruppati in cluster per il failover e la resilienza. Il passaggio in produzione di un'applicazione di microservices richiede un'infrastruttura di monitoraggio e operazioni di alta qualità.

  • La suddivisione dei servizi in un'architettura di microservizi consente all'applicazione di eseguire più funzioni contemporaneamente. Tuttavia, poiché i moduli vengono eseguiti come servizi isolati, viene introdotta una latenza nel tempo di risposta a causa delle chiamate di rete tra i servizi.

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

Quando decidi se l'architettura di microservizi è la scelta migliore per la tua applicazione, prendi in considerazione i seguenti punti:

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

Quando eseguire la migrazione di un'applicazione monolitica ai microservizi

Se stai già utilizzando un monolite, l'adozione dei microservizi comporta un costo di investimento significativo per il tuo team. I diversi team implementano i principi dei microservizi in modi diversi. Ogni team di ingegneria ha risultati unici per quanto riguarda le dimensioni dei microservizi o il numero di microservizi di cui ha bisogno.

Per determinare se i microservizi sono l'approccio migliore per la tua applicazione, innanzitutto identificate gli obiettivi commerciali principali o i problemi che vuoi risolvere. Potrebbero esserci modi più semplici per raggiungere i tuoi obiettivi o risolvere i problemi che hai identificato. Ad esempio, se vuoi aumentare la scalabilità della tua applicazione più velocemente, potresti scoprire che la scalabilità automatica è una soluzione più efficiente. Se riscontri bug in produzione, puoi iniziare implementando i test di unità e l'integrazione continua.

Se ritieni che un approccio basato su microservizi sia il modo migliore per raggiungere i tuoi scopi, inizia estraendo un servizio dal monolite e sviluppalo, testalo ed eseguine il deployment in produzione. Per ulteriori informazioni, consulta il documento successivo di questa serie, Eseguire il 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 a imparare da ogni ciclo.

Il pattern di architettura dei microservizi suddivide 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ò rallentare lo sviluppo del software. Quando implementi un'architettura di microservizi, consenti a team piccoli e autonomi di lavorare in parallelo, il che può accelerare lo sviluppo.

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

Passaggi successivi