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à:


·       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


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.

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.

Commenti

Post popolari in questo blog

Azure Service Bus Topics

R – regressione lineare semplice

Polly.NET