E’ da tempo ormai che, per la realizzazione di applicazioni complesse come un gestionale o un programma operativo, non si segue più un modello monolitico, ossia un’unica unità di codice che comprende al suo interno tutte le funzionalità. Si preferisce scomporre il sistema in piccole componenti (servizi) che siano indipendenti una dall’altra e interoperabili. Si parla quindi di architettura a microservizi.
In pratica il sistema viene scomposto in tante applicazioni indipendenti, ognuna delle quali svolge un solo compito e, scambiando dati con le altre, fornisce le stesse funzionalità che avrebbe avuto il sistema monolitico.
I vantaggi di questa scelta sono molteplici:
- Scalabilità: Ognuno dei microservizi può essere scalato in modo indipendente dagli altri, cioè le risorse disponibili possono essere assegnate in base alla criticità e alle richieste di un servizio.
- Facilità di sviluppo: Ciascun servizio può essere sviluppato, modificato e corretto in modo indipendente dagli altri.
- Facilità di integrazione e di aggiornamento: I servizi possono essere aggiornati, modificati e corretti in modo indipendente. Questo rende il sistema più adattabile alle esigenze degli utenti.
- Isolamento degli errori: Se su una componente si verifica un errore è più facile isolarlo e correggerlo. Inoltre l’impatto sul resto del sistema è minimo.
- Velocità di sviluppo: Ognuno dei servizi può essere sviluppato da team diversi, in parallelo e con tecnologie diverse.
- Facilita di test: E’ più sempliuce testare il funzionamento dei singoli microservizi, pur essendo necessario creare dei mockup delle componenti con cui interagisce.
Ci sono anche degli svantaggi:
- Consistenza dei dati: Poiché i team lavorano in modo indipendente è necessario che il passaggio dei dati tra i servizi sia progettato in modo attento, approfondito e condiviso.
- Coordinamento tra i team: Sincronizzare il lavoro di tanti team è più difficile.
- Test di integrazione: I test di integrazione sono complessi perché prevedono l’interazione tra programmi realizzati da persone diverse e con tecnologie diverse.
- Gestione del sistema: Per gestire un sistema così complesso è necessario un software che automatizzi la sua messa in opera.
- Overhead della comunicazione: I servizi per comunicare tra di loro usano la rete che quindi è sottoposta a un traffico notevole.
- Costo del sistema: Un sistema a microservizi richiede un’infrastruttura complessa e una serie di figure professionali (devops) che si occupino a tempo pieno della sua configurazione, del suo funzionamento e del suo monitoraggio.
Gli aspetti chiave dello sviluppo di un sistema di questo tipo e le sfide da affrontare sono le seguenti:
- Individuare correttamente i microservizi.
- Gestire la comunicazione tra i microservizi.
- Garantire la sicurezza del sistema.
- Monitorare lo stato del sistema.
Individuare correttamente i microservizi
La divisione del servizio in microservizi deve essere fatta in modo oculato. Il sistema va diviso in base alle funzionalità in modo che ogni sottosistema sia indipendente da un punto di vista logico prima che funzionale. Si deve pensare alle varie unità come vere e proprie applicazioni indipendenti. E’ importante che ognuna di queste applicazioni svolga uno ed un solo compito e non dipenda da nessuna delle altre.
Gestire la comunicazione tra i microservizi
Il problema chiave della realizzazione di un sistema a microservizi è certamente quello della comunicazione tra le varie componenti. Le soluzioni più usate sono:
- Utilizzo di una API (comunicazione sincrona): Ogni applicazione espone una serie di end-point per la scrittura e la lettura di dati. Quindi il modulo checkout, per esempio, può ottenere l’elenco degli oggetti presenti nel carrello, utilizzando l’end-point getItems del modulo carrello. La tecnologia più usata per realizzare una API è sicuramente REST. Ma ce ne sono anche altre come SOAP (che personalmente ritengo ormai obsoleta), RPC e GraphQL [8].
- Utilizzo di un broker di messaggi (comunicazione asincrona): In questo caso c’è un componente chiamato Message Broker che fa da intermediario. Si utilizza un protocollo di tipo publisher/subscriber in cui tutti i messaggi sono inviati al broker il quale li smista al destinatario corretto in base a un meccanismo basato sui canali di sottoscrizione. Una implementazione di questa forma di comunicazione è il protocollo MQTT, molto usato nell’Iot.
- Utilizzo di un “service mesh”: E’ un servizio offerto da molte infrastrutture cloud commerciali. In questo caso ad ogni servizio è associato un gateway (o sidecar) che si occupa dell’invio e della ricezione di tutti i messaggi. Esistono poi altre due componenti il Data Plane che comprende tutti i gateway e si occupa dell’instradamento dei messaggi e il Control Plane che si occupa della configurazione del Data Plane e quindi delle politiche di routing, della sicurezza e del monitoraggio. Una delle implementazioni più diffuse è Istio.
Garantire la sicurezza del sistema
Un sistema a microservizi funziona grazie al fatto che le varie componenti scambiano messaggi tra di loro. Questo passaggio di informazioni deve avvenire in modo sicuro e protetto. Le comunicazioni perciò devono come minimo essere protette da una qualche forma di autenticazione e di crittografia. Ognuno dei protocolli di cui si è parlato nel paragrafo precedente, oltre a questi due meccanismi di sicurezza basica, ne possiede degli altri più avanzati. Un altro accorgimento per aumentare la sicurezza potrebbe essere, per esempio, quello di fare in modo che le richieste siano accettate solo da alcuni indirizzi IP.
Monitorare lo stato del sistema
Un sistema costituito da così tante componenti non è facile da gestire, per questo servono una infrastruttura adeguata ma anche dei tool che permettano di individuare rapidamente eventuali errori, incongruenze o rallentamenti. Esistono vari programmi che possono essere utilizzati per questo scopo: Prometheus, Zabbix, Nagios, ecc.
Migrazione da un sistema monolitico a uno a microservizi
La sfida che molte software house hanno affrontato durante gli ultimi anni o stanno affrontando in questi giorni è quella del passaggio di vecchie mastodontiche applicazioni monolitiche ad applicazioni a microservizi. Rifare un software complesso da zero è una sfida enorme e troppo rischiosa, la soluzione più intelligente e meno rischiosa è quella di individuare le componenti logiche di cui è composto il sistema e isolarle, realizzarle, testarle e integrarle gradualmente uno alla volta. E’ una strada lunga, ma è l’unica che aumenta le possibilità di successo.
Fonti e riferimenti:
- [1] The twelve factor app.
- [2] Microservices explained su TechWorld with Nana.
- [3] 10 DevOps Tools you need to know su TechWorld with Nana.
- [4] Pattern: Microservice Architecture su Microsercives.io.
- [5] Introducing Assemblage – a microservice architecture definition process su Microsercives.io.
- [6] What are microservices? su Microsercives.io.
- [7] Microservices Architecture: Il Pattern Architetturale Emergente Per Le Grandi Applicazioni Moderne di Giuseppe Capodieci.
- [8] SOAP vs REST vs RPC vs GraphQL su GlueLsbs.com.
- [9] Cos’è un mesh di servizi? su Aws.amazon.com.