L'ampia varietà di servizi offerti da AWS permette spesso di realizzare la stessa funzionalità in modi diversi. Per i sistemi di messaggistica, AWS mette a disposizione servizi come Simple Notification Service (SNS), Simple Queue Service (SQS), EventBridge, Kinesis e Managed Streaming for Apache Kafka (MSK). A prima vista può sembrare che almeno una parte di questi servizi svolga le stesse funzioni. In questo articolo voglio illustrare la mia architettura di riferimento e spiegare perché, a mio parere, rappresenta la soluzione più semplice, conveniente e robusta nella maggior parte dei casi.
Event-Driven Architecture
I componenti di un sistema event-driven comunicano pubblicando eventi e sottoscrivendoli. L'integrazione asincrona porta con sé vantaggi non funzionali significativi. Disaccoppia, ad esempio, i cicli di vita dei componenti integrati. Entro certi limiti, il sistema continua a funzionare anche quando alcuni dei suoi servizi non sono disponibili, riducendo così l'overhead di coordinamento necessario per rilasciare componenti aggiornati e far evolvere il sistema.
Un'integrazione event-driven di base si compone di due parti: un componente del sistema può pubblicare eventi che descrivono accadimenti rilevanti del proprio ciclo di vita e può reagire (sottoscriversi) agli eventi pubblicati da altre parti del sistema. Vediamo quali servizi gestiti possiamo sfruttare per implementarla.
Pubblicazione: SNS
AWS Simple Notification Service (SNS) è un servizio completamente gestito che consente di inviare notifiche destinate ad altri componenti del sistema. La sua natura serverless e i costi contenuti lo rendono un ottimo candidato per la pubblicazione degli eventi. La Figura 1 mostra un servizio chiamato "Producer" che pubblica i propri eventi tramite un topic SNS.

Figura 1: il servizio "Producer" pubblica eventi su un topic SNS.
E il servizio "Consumer" sulla destra della figura? Come può sottoscrivere i messaggi pubblicati dal Producer?
SNS supporta la consegna dei messaggi tramite diversi protocolli: HTTP, attivazione di funzioni AWS Lambda, SMS e altri. Sulla carta, può sembrare ragionevole che il Consumer esponga un endpoint HTTP e lo utilizzi come destinazione del topic SNS, come illustrato nella Figura 2.

Figura 2: un topic SNS può inoltrare i messaggi a endpoint HTTP. Ma è davvero la soluzione ottimale?
È davvero la scelta migliore? Ipotizzando che i due servizi, Producer e Consumer, appartengano a team diversi, chi è responsabile del topic SNS? Il team del Producer deve assicurarsi che il topic sia configurato correttamente per ricevere i propri messaggi, mentre i team responsabili dei servizi consumer devono garantire che le destinazioni siano sempre corrette. Una proprietà condivisa di questo tipo è una ricetta sicura per generare attriti. Valutiamo un'alternativa.
Sottoscrizione: SQS
AWS SQS è una coda di eventi completamente gestita che trattiene temporaneamente i messaggi (eventi) generati dai producer fino a quando non vengono elaborati dai consumer. Permette una gestione distribuita degli eventi con bilanciamento del carico tra più consumer, aspetto fondamentale per garantire la fault tolerance nei flussi event-driven. A mio parere offre anche una visibilità sulle code molto maggiore rispetto ai topic SNS, oltre a un controllo agevole sulle modalità di consegna dei messaggi ai consumer.
Poiché SQS è una delle destinazioni supportate dai topic SNS, configuriamo una coda per i messaggi che dovranno essere elaborati dai servizi "Consumer", come illustrato nella Figura 3.

Figura 3: utilizzo di SQS come meccanismo di consumo degli eventi.
Con questa configurazione, i confini di responsabilità sono chiari:
- Il topic SNS usato per pubblicare i messaggi appartiene al team responsabile del servizio di origine (Producer).
- La coda SQS usata per consumare i messaggi appartiene al team responsabile del servizio sottoscrivente (Consumer).
La separazione delle responsabilità tra i due servizi deve riflettersi nell'architettura del sistema.
SNS + SQS: una EDA semplice
È opinione condivisa che un microservizio debba consentire l'accesso ai propri dati attraverso un'interfaccia pubblica ben definita, mentre il database va considerato un dettaglio implementativo da nascondere ai consumer. Un'incapsulazione così rigorosa del meccanismo di persistenza permette confini di responsabilità più netti, maggiore flessibilità nell'evoluzione dei microservizi e un controllo molto più ampio sulle interfacce pubbliche.
Il bus di messaggi utilizzato dal sistema è semplicemente un altro meccanismo di persistenza — anche se molto più limitato — e va trattato come tale. Di conseguenza, oltre al database, ogni (micro)servizio ha bisogno di un topic SNS per pubblicare gli eventi e di una coda SQS per consumarli, come illustrato nella Figura 4:

Figura 4: una EDA richiede di definire confini di responsabilità chiari non solo per i database, ma anche per i loro meccanismi di messaggistica (SNS e SQS).
Le frecce che collegano i servizi — le sottoscrizioni dai topic alle code — appartengono a un livello di astrazione architetturale superiore rispetto ai servizi stessi. Si può ad esempio prevedere un template CloudFormation per ciascun servizio e un template CloudFormation di livello superiore per il sistema risultante. È quest'ultimo a definire le sottoscrizioni.
Vale la pena ricordare che una sottoscrizione non implica che tutti gli eventi pubblicati vengano riversati ciecamente sui consumer: una sottoscrizione può specificare un filtro per inoltrare a ciascun consumer solo gli eventi rilevanti.
Questo approccio è in linea con il principio smart endpoints, dumb pipes, fondamentale per la semplicità e la flessibilità dei sistemi distribuiti. Secondo questo principio, l'intelligenza — la logica — deve risiedere nei servizi stessi (gli endpoint), non nei componenti infrastrutturali usati per l'integrazione (le pipe). Le pipe — l'infrastruttura di messaggistica e i canali di comunicazione — devono limitarsi a trasportare in modo affidabile i dati tra i servizi. L'obiettivo è ridurre le dipendenze tra i servizi, semplificando scalabilità, debug e velocità di sviluppo, evitando al tempo stesso i colli di bottiglia e la complessità tipicamente associati ai middleware più sofisticati.
È quindi il momento di parlare delle altre opzioni di messaggistica disponibili su AWS.
Servizi alternativi per la consegna dei messaggi
Come anticipato nell'introduzione, AWS offre molte altre soluzioni gestite legate alla messaggistica. Vorrei qui passare brevemente in rassegna le altre opzioni e spiegare perché, secondo me, la soluzione descritta sopra è la più adatta nell'80% dei casi.
EventBridge
La prima "S" di SNS e SQS sta per "simple", e non a caso: SNS e SQS sono servizi semplici. EventBridge è molto più flessibile nelle regole di filtro e di instradamento dei messaggi. A mio parere si avvicina al concetto di enterprise message bus dell'epoca SOA. Invece di pipe minimali, si ottiene un punto centrale per ricevere e instradare gli eventi tra tutti i componenti del sistema, e persino tra più sistemi. EventBridge ha naturalmente i suoi casi d'uso — ad esempio, quando occorre integrarsi con sistemi di terze parti.
Kinesis e MSK (Managed Kafka)
Sia Kinesis sia MSK sono servizi pensati per lavorare con dati in streaming. Si può dire che lo streaming di dati sia un sottoinsieme dell'event-driven architecture: in entrambi i casi si tratta di gestire messaggi pubblicati e consumati in modo asincrono. Tuttavia il pattern d'uso è diverso: mentre la EDA tradizionale si concentra su singoli eventi o messaggi, lavorare con dati in streaming significa elaborare flussi continui di eventi correlati, che le soluzioni tradizionali di message bus potrebbero non gestire altrettanto efficacemente. Da qui l'esistenza di strumenti come Kinesis e MSK. Se non occorre elaborare flussi continui di messaggi, strumenti più semplici come SNS e SQS porteranno a un sistema più lineare.
Amazon MQ
Amazon MQ è un servizio gestito di message broker per protocolli come ActiveMQ e RabbitMQ. È particolarmente utile per migrare sistemi legacy verso il cloud o per sistemi che devono essere eseguiti senza modifiche su più ambienti cloud. Pur offrendo un message broker completo con supporto per pattern avanzati, Amazon MQ comporta un overhead operativo e una complessità aggiuntivi rispetto alla semplicità di SNS e SQS.
Articoli della serie
- Event-Driven Architecture su AWS, Parte I: le basi (articolo corrente)
- Event-Driven Architecture su AWS, Parte II: le basi avanzate
- Event-Driven Architecture su AWS, Parte III: le basi più complesse
Pubblicato originariamente su https://vladikk.com .
In questo articolo abbiamo visto come implementare una event-driven architecture (EDA) su AWS utilizzando SNS e SQS per pubblicare e consumare eventi. Abbiamo mostrato come SNS e SQS, insieme, formino una soluzione semplice ed economica con confini di responsabilità chiari, offrendo flessibilità e fault tolerance.