Azure Service Bus
Introduzione
Un Enterprise Service Bus ha lo scopo di disaccoppiare le applicazioni client per mezzo di un middleware di comunicazione attraverso il quale possano scambiarsi dei messaggi; il middleware è un canale su cui un client può pubblicare un messaggio per farlo arrivare ad un altro client collegato sul medesimo canale. A differenza di un’integrazione tra client di tipo punto a punto, l’ultilizzo di questa architettura fornisce un unica struttura centralizzata per monitorare lo scambio dei messaggi e non richiede lo sviluppo di codice specifico per ciascun client da integrare. Il disaccoppiamento tra i client avviene per mezzo di messaggi che molto spesso contengono al loro interno la serializzazione in formato xml/json di un oggetto. Un adapter viene solitamente posto dininazi ai vari client proprio al fine di serializzare/deserializzare il messagio rispettivamente inviato o ricevuto.
Azure Service Bus
Il service bus di Azure ci mette a disposizione l’infrastruttura
che permette di connettere i nostri client (come illustrato nell’introduzione) attraverso
lo scambio di messaggi su una soluzione cloud-based. I client possono essere
servizi che girano anch’essi su Azure (ad esempio i classici Worker Role), ma
anche nostre applicazioni on premise. Le API esposte fanno da facade per l’accesso all’infrastruttura
facilitando il compito di pubblicare e ricevere messaggi per i client.
Fondamenti
Namespaces: sono dei contenitori per uno o più dei possibili meccanismi di comunicazione
che sono illustrati di seguito.
Meccanismi di comunicazione: il service bus espone 4 differenti meccanismi
per connettere applicazioni client, ciascuno con le sue peculiarità:
Ogni messaggio possiede un identificativo univoco, un MessageId, tramite il quale i meccanismi, illustrati precedentemente, possono funzionare. Uno degli aspetti più importanti delle Queues è che permettono ai client di comunicare tra di loro anche se non sono entrambi disponibili nello stesso momento. È il Service Bus che si occupa di inoltrare il messaggio al client non appena diventi di nuovo raggiungibile; inoltre l’utilizzo di più Receiver può essere sfruttato per scenari di load-balancing visto che i messaggi vengono inoltrati, dal Service Bus, al primo dei Receiver disponibili.
Esempio
Pronto il Namespace, possiamo passare a Visual Studio; l’obbiettivo è quello di creare due Console Application le quali fungano rispettivamente da Sender e da Receiver su di una coda creata nel Namespace “bloggertest” di cui sopra. All’interno di entrambi i progetti si deve referenziare la libreria WindowAzure.ServiceBus tramite NuGet.
Il passaggio successivo prevede l’aggiornamento dell’App.config per quanto riguarda la sezione appSettings, dove, relativamente alla chiave “Microsoft.ServiceBus.ConnectionString” è necessario inserire la stringa di connessione recuperata dal portale di Azure.
Receiver
L’applicazione che fa da Receiver è anch’essa una Console Application ed all’interno del suo App.config inseriamo la medesima stringa di connessione della precedente applicazione Sender.
La prima è identica a quella eseguita per il Sender, vale a dire che leggo la stringa di connessione e inizializzo il QueueClient. Successivamente imposto l’oggetto OnMessageOptions specificando che è responsabilità del mio codice gestire la segnalazione di completamento della gestione del messaggio o di non riuscita dell’operazione (tramite i metodi Complete ed Abandon). Il codice registra infine il delegate per gestire la ricezione di un messaggio; al suo interno è possibile vedere quanto sia semplice deserializzare l’oggetto ricevuto e leggerne le proprietà.
Conclusioni
Le code ci forniscono un meccanismo semplice per mettere in comunicazione due applicazioni tramite l'invio di messaggi che tengono le applicazioni slegate e ignoranti l'una dell'altra. Nei prossimi articoli illustrerò il funzionamento di Topic, Relays ed Event Hubs.
· Queues: forniscono una comunicazione punto a punto monodirezionale.
Questo vuol dire che un solo client può ricevere il messaggio e non ha
possibilità di inviare una risposta.
· Topics: anch’esse mettono a disposizione un tipo di
comunicazione monodirezionale; tuttavia, nel rispetto del pattern publish-subscribe,
più di un client può registrarsi per ricevere lo stesso messaggio.
· Relays: la comunicazione è di tipo bidirezionale. A differenza
delle Queues e dei Topics, che conservano i messaggi inviati fino
a quando i client non li hanno ricevuti, i Relays passano
il messaggio all’applicazione destinataria se disponibile
· Event Hubs: sono da preferirsi negli scenari IOT dove sia necessario
inviare un gran numero di eventi sfruttando un canale affidabile e con bassa
latenza.
Qualunque sia il meccanismo scelto, sarà necessario
specificare un nome che (insieme al Namespace) identificherà in modo univoco il
nostro oggetto. Per sfruttare i servizi offerti da Queues, Topics
ed Event
Hubs esistono delle API dedicate;
per quanto riguarda i Relays è
necessario WCF.
Come detto in precedenza, sebbene il Service Bus
giri sui data center di Windows Azure, i client che vogliano utilizzare i suoi
servizi possono trovarsi non solo su Azure ma anche su server on premise, o
essere dei sensori, dei device mobile, …
Queues
Queues
Il presente articolo
prende in esame il primo meccanismo tra i quattro illustrati precedentemente. Il
principio è molto semplice: un Sender invia
il messaggio al Service Bus tramite una coda ed in un secondo momento un Receiver
ed uno solo tra quelli in ascolto sulla stessa coda, lo recupera e lo gestisce.
Le Queues
di fatto si prestano ad agire come un broker (intermediario) tra le varie
applicazioni di un sistema distribuito. Il Sender, dopo aver inviato il messaggio,
continua con le sue operazioni senza attendere una risposta dal Receiver o un feedback circa l’esito dell’invio. Siamo
quindi in uno scenario di tipo fire and forget. I messaggi vengono gestiti
dal Service Bus secondo il paradigma FIFO (first-in,
first-out).
I
messaggi inviati sono composti da due parti
1. Un
Dictionary
contenente delle coppie chiave/valore
2. Un contenuto binario che può anche essere lasciato vuoto
Il Sender deciderà
in base alle esigenze del caso specifico se popolare uno o entrambi i
componenti. Ad esempio il contenuto di un messaggio potrebbe essere la
scansione di un documento firmato e nel Dictionary potremmo aggiungere informazioni relative al cliente o al numero
del contratto.
Il Receiver può leggere
il messaggio in due modi:
· 1. ReceiveAndDelete, in questa modalità il messaggio, una volta
ricevuto, viene cancellato anche laddove ci dovesse essere un crash da parte
del Receiver durante la sua gestione.
· 2.
PeekLock, come nel primo caso il messaggio viene letto e
rimosso dall’accodamento del Service Bus, tuttavia non viene cancellato immediatamente
ma possono verificarsi 3 scenari:
1.
Se il Receiver processa correttamente il messaggio e chiama il
metodo Complete,
allora il messaggio viene cancellato
2.
Se il Receiver decide di non poterlo gestire e chiama il metodo Abandon,
allora il messaggio viene inviato ad un altro Receiver
se disponibile
3. Se nessuno dei due metodi precedenti dovesse essere
chiamato in un certo tempo (configurabile), la coda si comporta come se il Receiver fosse andato in errore e pertanto rende il
messaggio disponibile per altri Receiver proprio
come se il metodo Abandon fosse stato
chiamato
Ogni messaggio possiede un identificativo univoco, un MessageId, tramite il quale i meccanismi, illustrati precedentemente, possono funzionare. Uno degli aspetti più importanti delle Queues è che permettono ai client di comunicare tra di loro anche se non sono entrambi disponibili nello stesso momento. È il Service Bus che si occupa di inoltrare il messaggio al client non appena diventi di nuovo raggiungibile; inoltre l’utilizzo di più Receiver può essere sfruttato per scenari di load-balancing visto che i messaggi vengono inoltrati, dal Service Bus, al primo dei Receiver disponibili.
Esempio
La prima operazione da
svolgere per collegarsi al Service Bus è accedere al portale di Azure con la
propria sottoscrizione e creare un Namespace che
faccia da contenitore per la nostra Queue.
La videata precedente mostra che ho creato una Namespace “bloggertest”. Come sottolineato dalla documentazione
di Microsoft, è caldamente consigliato creare il Namespace nella stessa area
geografica in cui gireranno le altre applicazioni che sfrutteranno la coda
stessa; questo per ovvi motivi di performance. Una volta cliccato sul pulsante “Crea
Inoltro”, la videata successiva ci mostra la fase di attivazione del servizio.
Completata l’attivazione possiamo recuperare la
stringa di connessione alla coda cliccando sulla voce “Informazioni di
connessione” che si trova al centro della barra al fondo della pagina del
portale. La modal che appare mostra la stringa che copieremo nel file
App.config delle nostre applicazioni “Sender” e “Receiver”.
Pronto il Namespace, possiamo passare a Visual Studio; l’obbiettivo è quello di creare due Console Application le quali fungano rispettivamente da Sender e da Receiver su di una coda creata nel Namespace “bloggertest” di cui sopra. All’interno di entrambi i progetti si deve referenziare la libreria WindowAzure.ServiceBus tramite NuGet.
Il passaggio successivo prevede l’aggiornamento dell’App.config per quanto riguarda la sezione appSettings, dove, relativamente alla chiave “Microsoft.ServiceBus.ConnectionString” è necessario inserire la stringa di connessione recuperata dal portale di Azure.
<appSettings>
<!-- Service Bus specific app setings for messaging
connections -->
<add key="Microsoft.ServiceBus.ConnectionString" value="Endpoint=sb://bloggertest.servicebus.windows.net/;SharedAccessKeyName=…"/>
</appSettings>
Sender
Il codice (contenuto nel metodo Main) è piuttosto semplice: dopo aver letto la stringa di connessione dalla configurazione, inizializzo un Namespace tramite la classe NamespaceManager che fa da Factory. Verifico quindi, se sia necessario creare la coda (la prima volta che ci accedo potrebbe non esistere ancora nel Namespace scelto) e quindi inizializzo il client tramite l’oggetto QueueClient. Infine, creo il messaggio da inviare, il BrokeredMessage, il cui costruttore ammette (oltre ad un costruttore vuoto) l’inizializzazione tramite uno Stream o un Object (ovviamente deve essere serializzabile) che rappresentano il nostro contenuto binario di cui abbiamo parlato all’inizio dell’articolo. Ho aggiunto anche una Property al Dictionary per tracciare la data ed ora di creazione del messaggio.
Sender
Il codice (contenuto nel metodo Main) è piuttosto semplice: dopo aver letto la stringa di connessione dalla configurazione, inizializzo un Namespace tramite la classe NamespaceManager che fa da Factory. Verifico quindi, se sia necessario creare la coda (la prima volta che ci accedo potrebbe non esistere ancora nel Namespace scelto) e quindi inizializzo il client tramite l’oggetto QueueClient. Infine, creo il messaggio da inviare, il BrokeredMessage, il cui costruttore ammette (oltre ad un costruttore vuoto) l’inizializzazione tramite uno Stream o un Object (ovviamente deve essere serializzabile) che rappresentano il nostro contenuto binario di cui abbiamo parlato all’inizio dell’articolo. Ho aggiunto anche una Property al Dictionary per tracciare la data ed ora di creazione del messaggio.L’applicazione che fa da Receiver è anch’essa una Console Application ed all’interno del suo App.config inseriamo la medesima stringa di connessione della precedente applicazione Sender.
La prima è identica a quella eseguita per il Sender, vale a dire che leggo la stringa di connessione e inizializzo il QueueClient. Successivamente imposto l’oggetto OnMessageOptions specificando che è responsabilità del mio codice gestire la segnalazione di completamento della gestione del messaggio o di non riuscita dell’operazione (tramite i metodi Complete ed Abandon). Il codice registra infine il delegate per gestire la ricezione di un messaggio; al suo interno è possibile vedere quanto sia semplice deserializzare l’oggetto ricevuto e leggerne le proprietà.
Conclusioni
Le code ci forniscono un meccanismo semplice per mettere in comunicazione due applicazioni tramite l'invio di messaggi che tengono le applicazioni slegate e ignoranti l'una dell'altra. Nei prossimi articoli illustrerò il funzionamento di Topic, Relays ed Event Hubs.







Commenti
Posta un commento