Definiamo i microservizi come uno stile architetturale che decompone le funzionalità di un’applicazione in un insieme di servizi, ognuno dei quali è focalizzato e dedicato ad una singola funzionalità e che presenta un accoppiamento lasco con i restanti servizi. Queste architetture, essendo caratterizzate dalla presenza di molteplici servizi, dovranno implementare specifici meccanismi di comunicazione al fine di realizzare le diverse funzionalità. Generalmente si cerca di ottenere un livello di granularità molto basso per singolo servizio quindi una o più funzionalità impatterà inevitabilmente su più servizi, fermo restando che si dovranno progettare soluzioni cercando di evitare catene di chiamate eccessivamente lunghe.
Possiamo distinguere due macro-modalità di comunicazione, la comunicazione sincrona e quella asincrona. Nella comunicazione sincrona tutti i partecipanti in una catena di chiamate rimangono in attesa della risposta. Di base il protocollo HTTP è sincrono, banalmente quindi un client invia una richiesta e attende la risposta prima di continuare con le sue attività.
Nella comunicazione asincrona invece il mittente del messaggio non aspetta attivamente la risposta del messaggio. Un esempio è il protocollo AMQP, nel quale il codice del client o del mittente del messaggio di solito non attende una risposta. Quello che fa è semplicemente inviare un messaggio a una coda (ad esempio RabbitMQ) o qualsiasi altro agent di messaggistica.
Generalmente si tende a mantenere sincrona esclusivamente la comunicazione tra il client, che può essere rappresentato da un qualsiasi front-end applicativo, e il primo strato di servizi, il quale è spesso identificato da un API Gateway, ovvero l’entità preposta al routing verso i microservizi dell’architettura e sulla quale vengono applicate le policy di sicurezza e di autorizzazione. Tutta la comunicazione interna dovrebbe invece essere asincrona in modo tale da disaccoppiare i singoli servizi e tenerli il più possibile indipendenti. Per ottenere questo livello di disaccoppiamento si utilizzano meccanismi di comunicazione specifici, ad esempio, attraverso l’utilizzo di code.
Utilizzare un sistema di comunicazione basato su code non è limitato al raggiungimento del disaccoppiamento tra le entità, ovvero tra il produttore e il consumatore del messaggio, ma permette di supportare frequenze differenti tra la produzione del dato e del successivo processamento, il tutto limitatamente alla teoria delle code e alle implicazioni della Legge di Little secondo le quali un sistema è stabile se la frequenza di arrivo è minore o uguale della frequenza di processamento. Ma, permettendo il disaccoppiamento tra produttore e consumatore, è possibile scalare in modo indipendente, supportando picchi di carico semplicemente scalando i servizi preposti al processamento dei messaggi. Un altro aspetto che contraddistingue le comunicazioni basate su code è la possibilità di processare i messaggi in modo FIFO, ovvero First-in-First-out, mantenendo quindi l’ordinamento secondo le priorità di arrivo del messaggio. Architetture basate su questo tipo di comunicazione risultano essere molto più resilienti, in quanto anche in caso di fault i messaggi sono persistiti all’interno della coda stessa e non vengono persi. Inoltre, una comunicazione basata su code viene spesso utilizzata come integrazione per progettare soluzioni hybrid cloud, mantenendo parte dei sistemi on-premises e migrando o estendendone alcuni in cloud.
Nelle comunicazioni tramite code, i consumatori dei messaggi accodati devono esplicitamente controllare la presenza di nuovi messaggi con meccanismi di polling più o meno complessi. Per realizzare una comunicazione di tipo event-driven, ovvero orientata agli eventi e real-time, si utilizzano soluzioni che utilizzano i message broker. Un message broker è un sistema che si pone tra due o più servizi della nostra architettura e ha il compito di ricevere i messaggi e di deliverarli. Il message broker ha al suo interno una coda nella quale persiste i messaggi ricevuti e li consegna ai servizi che sono interessati ad un particolare messaggio. I servizi consumatori del messaggio non dovranno quindi preoccuparsi di controllare esplicitamente la presenza di nuovi messaggi ma li riceveranno direttamente dal message broker stesso. Una delle particolarità nell’utilizzo di un message broker è che permette una comunicazione one-to-many, è possibile quindi implementare logiche di multicast, deliverando i messaggi al sottoinsieme di servizi interessati. Inoltre, sistemi di comunicazione che utilizzano message broker garantiscono l’affidabilità della consegna dei messaggi. Generalmente implementano infatti logiche del tipo At least Once Delivery, ovvero la garanzia che ogni servizio interessato riceverà prima o poi il messaggio almeno una volta.
L’utilizzo di soluzioni di messaging broker è alla base dei sistemi di tipo publish\subscribe, ovvero quella tipologia di sistemi che sono definiti come topic-based. Il modello publish/subscribe è un paradigma di interazione che vede coinvolte due entità: da un lato abbiamo quelli che si definiscono produttori chiamati publisher e dall’altro quelli che si definiscono consumatori, chiamati subscriber (o sottoscrittori). I primi rappresentano i componenti attivi del sistema in grado di generare messaggi che si dovranno poi diffondere, mentre i secondi rappresentano i componenti passivi del sistema, i quali ricevono le informazioni di interesse. In pratica tale modello di interazione consente ai sottoscrittori di esprimere i propri interessi verso un certo tipo di evento (o un pattern di eventi) chiamato topic, con lo scopo di essere successivamente notificati con eventi compatibili con quelli che sono gli interessi espressi. In altre parole, i produttori pubblicano informazioni su un canale di eventi (bus) e i sottoscrittori si sottoscrivono per l’appunto al canale per ricevere informazioni di loro interesse. È importante specificare che i publisher e i subscriber non si escludono a vicenda, nel senso che un subscriber può all’occorrenza divenire un publisher e viceversa. Questa tipologia di sistemi permette di ottenere tre livelli di disaccoppiamento, il disaccoppiamento spaziale, quello temporale e di sincronizzazione.
Quando si progetta una architettura a microservizi, la comunicazione tra i servizi gioca un ruolo fondametale, non solo dal punto di vista delle prestazioni, ma soprattutto dal punto di vista dell’affidabilità. La scelta della modalità di comunicazione è chiaramente dipendente dal contesto applicativo. Un approccio spesso utilizzato è quello di combinare diversi stili di comunicazione, ottenendo un buon compromesso tra facilità di integrazione, affidabilità e performance.
Risorse:
https://sharpcoding.medium.com/