CARATTERISTICHE SALIENTI DELLO STANDARD JMS

Transcript

CARATTERISTICHE SALIENTI DELLO STANDARD JMS
0000223986 Andrea Ceruti
Reti di calcolatori LS
Sviluppo di un’infrastruttura di supporto per
aste in tempo reale tramite l’utilizzo di un
middleware orientato ai messaggi.
Abstract
Questa relazione documenta il lavoro svolto per il corso di Reti di calcolatori LS e
intende riassumere le scelte che hanno guidato la realizzazione di un’infrastruttura di
supporto per aste in tempo reale. Il progetto è nato dal desiderio di approfondire le
caratteristiche di un Message Oriented Middleware e si propone di analizzare le
possibilità offerte dai MOM nella realizzazione di applicazioni che beneficino del
disaccoppiamento tra le parti offerto da infrastrutture a messaggi.
L’ infrastruttura sviluppata è una piattaforma di compravendita utilizzabile dalle case
d’asta per realizzare vendite online in diretta. L’idea è nata dal desiderio di simulare il
funzionamento della piattaforma LIVE AUCTION di Ebay e dal sogno di poter occupare
in futuro un piccolo posto nello spazio competitivo che si libererà quando la società
americana chiuderà il servizio, ritenuto marginale in termini di fatturato. Il presente
lavoro si è prefisso l’obiettivo di realizzare un’ architettura affidabile che garantisca
efficienza, disponibilità e tolleranza ai guasti, requisiti indispensabili per questo tipo di
applicazione.
Introduzione
Il progetto è stato realizzato utilizzando le API di Java Message Service (JMS) e
sfruttando le funzionalità messe a disposizione dal Message Oriented Middleware
(MOM) ActiveMQ, un middleware open source che supporta le specifiche 1.1 di JMS.
Un middleware cooperativo è un componente software che si posiziona in un’architettura
di rete tra lo strato di trasporto e quello di applicazione per facilitare l’elaborazione
cooperativa: viene richiamato dall’applicazione in fase esecutiva e sgrava l’applicazione
da pesanti compiti di gestione non strettamente legati alle sue funzionalità operative
specifiche. Questo strato software funge da intermediario tra le diverse applicazioni,
fornendo ad esse un’interfaccia standard per usufruire dei propri servizi.
Ogni applicazione che usufruisce di un middleware può dunque essere sviluppata senza
preoccuparsi dei dettagli della comunicazione.
Un Message Oriented Middleware è una tecnologia di middleware che permette la
comunicazione con scambio di messaggi tra due o più applicazioni.
Le applicazioni non interagiscono direttamente tra di loro in quanto il mittente ed il
destinatario dell’informazione non devono necessariamente essere a conoscenza l’uno
dell’altro: è il MOM che riceve i messaggi dal produttore dell’informazione e li recapita
ai relativi consumatori dopo opportune trasformazioni. La caratteristica più rilevante di un
middleware orientato ai messaggi risiede dunque nella possibilità di asincronicità della
comunicazione, permettendo il disaccoppiamento spaziale e temporale fra i comunicanti:
mittente e ricevente per comunicare non devono necessariamente essere disponibili allo
stesso tempo (comunicazione distribuita debolmente accoppiata).
I messagging system supportano due modelli di base per la gestione dei messaggi: PointTo-Point e Publish/Subscribe.
Nel modello Point-To-Point il produttore invia messagi a una particolare coda (Queue) e
un consumatore legge i messagi da questa coda. In questo modello il produttore conosce
la destinazione dei messagi e invia i messagi direttamente alla coda del consumatore.
• Quando un mittente invia un messaggio a una Queue, essa lo consegna solo al
primo destinatario che cerca di ricevere un messaggio da quella Queue. Se nessun
destinatario è attivo per la Queue nel momento in cui un mittente invia un
messaggio, questo viene conservato dal Middleware finché non si attiva un
destinatario (o finché non scade il time-to-live del messaggio, se questo è stato
impostato).
• Ogni messaggio è ritenuto ricevuto (acknowledged) quando un consumatore lo ha
recuperato.
Il modello Publish/Subscribe supporta la pubblicazione di messaggi in un particolare
Topic. In questo modello, nè il publisher nè il subscriber sono a conoscenza l’ uno dell’
altro.
• Più consumatori possono ricevere il messaggio. Il modello consente quindi una
comunicazione uno-a-molti e si adatta bene in tutte quelle situazioni in cui è
imprecisato il numero delle entità che interagiscono nel sistema.
• C’è dipendenza temporale tra publisher e subscriber. Il publisher deve creare una
subscription affinche i subscriber possano registrarsi. Un subscriber che si è
sottoscritto ad un topic potrà consumare solamente messaggi pubblicati dopo la
sua sottoscrizione. Il subscriber deve rimanere contemporaneamente attivo per
ricevere i messaggi, a meno che non abbia stabilito una durable subscription. In
tal caso, i messagi pubblicati mentre il subscriber non è connesso vengono ricevuti
quando questo si riconnette.
JMS – generalità
JMS è un insieme di API che consentono lo scambio di messaggi tra applicazoni Java
distribuite nella rete. In sostanza JMS fornisce un metodo standard tramite il quale le
applicazioni possono creare, inviare e ricevere i messaggi usando un message oriented
middleware.
Un sistema architettato con JMS è costituito dai seguenti elementi:
• Client JMS: programma in linguaggio Java che invia o riceve messaggi JMS.
• Messaggio: raggruppamento di dati che viene inviato da un client a un altro.
• JMS Provider: sistema di messaggistica che implementa la specifica JMS e
realizza funzionalità aggiuntive per l’ amministrazione e il controllo della
comunicazione attraverso messaggi.
• Administered objects: sono oggetti preconfigurati da un amministratore ad uso
dei client. Incapsulano la logica specifica del JMS provider nascondendola ai
client, garantendo maggiore portabilita al sistema complessivo. Fanno parte del
middleware lato server e sono usati dai client per inizializzare la comunicazione.
• ConnectionFactory : è un administered object utilizzato da un client per
realizzare la connessione con il provider.
• Destination (queue/topic): è un administered object che svolge il ruolo di
“deposito” in cui i mittenti possono lasciare i messaggi che creano, e da cui i
destinatari possono recuperare i messaggi. Le destinazioni possono essere usate
contemporaneamente da più mittenti e da più destinatari. A seconda del tipo di
destinazione usato (queue o topic), la consegna dei messaggi avviene secondo
modalità diverse (point to point o publish/subscribe).
Le applicazioni JMS hanno qualità intrinseche che sono sintetizzabili in:
• Asincronicità della comunicazione : il provider JMS consegna i messaggi al
client appena quest’ ultimo si è reso disponibile. Il provider li consegna senza che
il receiver abbia effettuato una richiesta specifica.
• Affidabilità della comunicazione: JMS può assicurare che un messagio sia
consegnato una ed una sola volta.
• Disaccopiamento spaziale: grazie all’uso del sistema di naming di Java (JNDI)
non è necessario avere un riferimento diretto ad oggetti remoti, ma ci si affiderà
alla presenza degli administered object: la creazione di connection factory e
destination è compito dell’ amministratore JMS che deve inserirli all’interno di un
contesto JNDI in un opportuno namespace in modo che possano essere recuperati
da qualsiasi client mediante le API JNDI
• Quality of Service configurabile: le API JMS prevedono differenti livelli di
affidabilità per considerare molteplici scenari applicativi.
• Robustezza ai cambiamenti: sono presenti tipologie differenti di messaggi e
features personalizzabili.
Obiettivi dell’applicazione
Il progetto ha come obiettivo quello di ricostruire una sala virtuale distribuita sul web,
mediante una piattaforma che consenta di partecipare in diretta ad un’asta via internet.
A questo scopo è necessario che un’ applicazione svolga il ruolo di battitore dell’ asta: le
vendite devono essere gestite secondo un ordine prefissato accedendo ad un database
dove sono memorizzati i lotti dei vari cataloghi e occorre notificare gli offerenti sulle
informazioni che riguardano il lotto corrente.
Gli acquirenti, come è facile intuire,
devono poter accedere al servizio ed effettuare offerte sui lotti in tempo reale.
Il battitore dunque è un produttore di informazione che interagisce con gli offerenti
secondo una modalità di tipo push, ossia fornisce ai partecipanti informazioni riguardo i
lotti oggetto dell’ asta (ad esempio prezzo di base e descrizione), senza che questi ne
abbiano fatto esplicita richiesta; allo stesso tempo riceve dagli offerenti informazioni
riguardo le loro offerte, quali ad esempio valore dell’offerta
e
identificativo
dell’offerente.
Pertanto sia battitore che offerenti sono entrambi produttori e
consumatori di informazione, con l’unica differenza che il battitore deve produrre e
fornire informazioni ad un numero di client non noto a priori e potenzialmente enorme.
Un’ applicazione di questo tipo, caratterizzata da una comunicazione uno a molti di tipo
push-based con un numero imprecisato di client, si presta bene ad essere realizzata
utilizzando la tecnologia dei Java Message Serivce. Le api di JMS permettono infatti di
accedere ed utlizzare i servizi dei sistemi di messaggistica, che supportano il modello
publish/subscribe, adatto ad una comunicazione di tipo uno a molti.
In base a questo paradigma, quando un messaggio viene inserito in una destinazione di
tipo topic, può essere inviato a tutti i destinatari che si sono dichiarati interessati a
riceverlo effettuando una sottoscrizione: i messaggi vengono inviati in broadcast ai
consumer ed è il JMS provider che realizza l’operazione di dispatching dei messaggi a
tutti i client. Ciascuno di essi riceverà una copia identica del messaggio inviato al topic.
La tecnologia dei Java Message Service dunque si dimostra utile ai fini dell’
implementazione di un’ architettura efficace perchè supporta una comunicazione di tipo
uno a molti, caratteristica intrinseca del sistema. Inoltre fornisce un supporto per la
consegna affidabile e garantita dei messaggi, consentendo di implementare una soluzione
robusta.
Architettura logica del sistema
Sono due le categorie di utilizzatori del sistema:
• Il battitore (Admin)
• Gli offerenti (Bidder)
L’ applicazione Admin consiste di un’ interfaccia tramite la quale è possibile aprire i lotti
in ordine sequenziale. L’ apertura di un lotto corrisponde alla pubblicazione in un topic
di un messaggio contenente informazioni sul lotto in questione.
I bidder dopo aver effettuato una sottoscrizione durevole a questo topic ricevono da esso
le informazioni sui lotti e a loro volta pubblicano i messaggi corrispondenti alle loro
offerte. Il nucleo centrale del sistema è dunque composto da un topic in cui l’ Admin è
publisher di un messaggio chiamato Status contenente le informazioni sui lotti correnti e
i bidder sono i subscriber interessati a ricevere questo messaggio. A loro volta i bidder
sono publisher di un messaggio chiamato Bid contenente informazioni sulle offerte
effettuate e l’ Admin è il subscriber interessato a ricevere questo messaggio.
Struttura dei messaggi
Entrambe le applicazioni Bidder e Admin creano degli oggetti TextMessage che
incapsulano un documento XML come stringa Java. L’azione di offerta da parte del
bidder viene pertanto notificata nel topic con un messaggio XML avente la seguente
struttura:
<LiveAuctionMessage>
<Action> Bid </Action>
<BidderName> Andrea </BidderName>
<LotId> 1 </LotId>
<Base> 200 </Base>
<Price> 250 </Price>
<Title> moneta romana 2 secolo a.c. </Title>
</LiveAuctionMessage>
L’ Admin aggiorna lo stato ogni qual volta apre un lotto nuovo o quando viene pubblicato
nel topic un messaggio di offerta da parte di un bidder.
Il messaggio XML con cui viene notificato nel topic l’ aggiornamento dello stato ha la
seguente struttura:
<LiveAuctionMessage>
<Action> Status </Action>
<CurrentLot> 1 </CurrentLot>
<Base> 200 </Base>
<Title> moneta romana 2 secolo a.c. </Title>
<CurrentPrice> 250 </CurrentPrice>
<CurrentWinner> Andrea </CurrentWinner>
</LiveAuctionMessage>
Pubblicazione dei messaggi
Dal momento che le applicazioni coinvolte necessitano di “filtrare” i messaggi pubblicati
nel topic (Status o Bid), si è deciso di utilizzare un’importante proprietà della tecnologia
JMS: i message selector. Grazie a questa proprietà il consumatore specifica a quali
messaggi è interessato e il provider JMS invia selettivamente solo quei messaggi ai
client. Utilizzando i message selector dunque l’ onere di filtrare i messaggi è assegnato
al provider JMS piuttosto che all’ applicazione client.
Ciò ha il duplice vantaggio di ottimizzare il traffico di rete (riducendo il numero di
messaggi da inviare ad un determinato ascoltatore), e di migliorare il codice applicativo
permettendo di implementare consumatori più specifici. I message selector in sostanza
sono stringhe contenenti un’ espressione che utilizza la logica booleana per stabilire quali
messaggi debbano essere consegnati ai consumatori.
A livello applicativo un message selector viene specificato sia in fase di invio del
messaggio che in fase di creazione del consumatore. Nel nostro caso al momento della
creazione del messaggio viene aggiunta ad esso una string property di tipo ACTION, il
cui valore, settato tramite il metodo setStringProperty a ‘bid’ o ‘status’, identifica
l’applicazione interessata alla ricezione del messaggio stesso.
Dal lato subscriber, al momento della creazione di una sottoscrizione durevole, il metodo
createDurableSubscriber permette di specificare come argomento, non solo il nome del
topic e della sottoscrizione, ma anche il valore del selector: solo i messaggi con property
corrispondente al valore del selector argomento di questo metodo vengono consegnati dal
provider JMS.
I message selector usano l’header e i property fields di un messaggio JMS come criteri in
espressioni condizionali: il risparmio della banda del canale che si ottiene utilizzando i
message selector va dunque a scapito delle performance del sistema, in quanto header e
propeties del messaggio devono essere ricavati e successivamente paragonati dal provider
JMS. Data l’alta frequenza delle operazioni di offerta dei bidder e di aggiornamento dello
stato, si è preferito comunque utilizzare i message selector per evitare un eccessivo
traffico di rete ed un superfluo trattamento di messaggi da parte di applicazioni non
interessate alla ricezione di tutti i messaggi.
Si è deciso inoltre di ottimizzare la sessione scegliendo la modalità di “message
acknowledgement” AUTO_ACKNOWLEDGE.
Questa modalità realizza la politica della consegna dei messaggi once-and-only-once: si
può cosi ridurre il traffico di rete rispetto alle altre modalità che realizzano semantiche atleast-once, a scapito però di un overhead sul server JMS che deve attuare questa politica.
Il subscriber infatti definisce un message listener, ovvero una classe che implementa
l'interfaccia javax.jms.MessageListener e ridefinisce il metodo onMessage().
Ogni qualvolta un messaggio arriva alla destinazione d'interesse, è il provider JMS che
provvede ad invocare in maniera asincrona il metodo di callback onMessage(), alla cui
esecuzione la sessione riconosce automaticamente il messaggio.
All interno del metodo onMessage() viene invocato un parser xml il cui compito è
quello di estrarre dai messaggi di interesse le informazioni da visualizzare nell’
interfaccia grafica. L’ implementazione del subscriber, e quindi del metodo
onMessage(), è perciò concettualmente simile sia per il bidder che per l’ admin: ciò che
cambia tra le due tipologie di client è l’implementazione del parser xml che deve
analizzare due messaggi , ossia due stringhe xml diverse.
Guaranteed Message Delivery
Per aumentare il grado di reliability ed efficienza dell’ infrastruttura si sfrutta
un'importante caratteristica offerta dai sistemi MOM, il Guaranteed Message Delivery
che garantisce la consegna del messaggio, anche in caso di problemi al sistema.
Un eventuale crash o failure del server porterebbe ad un’ indesiderata perdita di
informazioni, inaccettabile per un’ applicazione in cui i messaggi rappresentano
transazioni economiche. È per questo motivo che i messaggi possono essere resi
persistenti (ad es: mediante JDBC) prima di essere recapitati ai consumatori.
A questo scopo è necessario in fase di pubblicazione settare il Delivery Mode del
messaggio a PERSISTENT. Si può impostare la modalità delivery sul singolo messaggio
mediante parametro nel metodo publish():
publish(<message>, DeliveryMode.PERSISTENT, <priority level>,
<expiration time>);
Entrambi i messaggi Bid e Status sono stati resi persistenti per assicurare che non
vengano persi in caso si verifichi un errore nel provider JMS; è lo stesso provider JMS
che si occupa di memorizzare opportunamente i messaggi.
Si è deciso inoltre di rendere le sottoscrizioni durevoli, in modo da consentire la ricezione
dei messaggi anche se il client non era in ascolto al momento della generazione del
messaggio. Le durable subscrpition rendono persistenti i subscriber: l’identificazione
univoca del subscriber consente infatti, in caso di crash del JMS provider e successivo
riavvio, di effettuare il resume del subscriber nello stato in cui era stato lasciato
precedentemente, riprendendo la ricezione dei messaggi.
Per questo motivo si è deciso di rendere durevole non solo la sottoscrizione al topic dei
bidder, ma anche quella dell’ Admin. L’ utilizzo delle durable subscription si dimostra
uile non solo in situazioni di recovery da guasti, ma anche perchè consente ad un bidder
di loggarsi al sistema ad asta avviata e ricevere ugualmente informazioni sul lotto
corrente, anche se non era in ascolto al momento della generazione del messaggio da
parte dell’ Admin.
Se infatti una sottoscrizione “durable” non ha subscriber attivi al momento, il JMS
provider memorizza tutti i messaggi finché un subscriber non si attiva e i messaggi
vengono ricevuti. La sottoscrizione persistente dura dall’istante di tempo in cui viene
creata fino all’istante in cui viene cancellata con il comando topicSession.unsubscribe().
Si definisce l’identità unica di un subscriber stabilendo:
• Un client ID per la connessione.
• Un topic e un nome della sottoscrizione per il subscriber.
Nel caso dei bidder si è settato l’ID dei bidder al valore corrispondente al numero IP della
macchina sui cui si è loggato l’ offerente; il settaggio viene impostato tramite il metodo
setClientId(String) di JMS applicato a un oggetto di tipo TopicConnection.
ActiveMQ
1. Persistenza
Se da un lato JMS offre la possibilità di specificare l’esatta Quality of Service di ogni
scambio di messaggi in termini di guaranteed delivery e di consegna tramite semantica
once-and-only-once, ActiveMQ mette a disposizione altre funzionalità per ottenere
affidabilità del sistema, high availability e tolleranza ai guasti.
ActiveMQ è un message broker open source che supporta le specifiche JMS 1.1.
Un broker è la parte di una soluzione JMS lato server che si occupa di routing, recovery,
persistenza e cosi’ via. Per quanto riguarda la persistenza, come detto precedentemente il
provider JMS memorizza i messaggi su un persistent storage se il delivery mode è stato
settato a persistent, di modo che sopravvivano a un riavvio del broker. Inoltre per
sopperire alla mancanza del servizio e permetterne la successiva riattivazione, il provider
JMS memorizza anche le durable subscriptions: se così non fosse il message server, in
caso di fallimento, non sarebbe capace di consegnare i messaggi ai durable subscribers
stessi. Per effettuare le operazioni di recovery il provider JMS:
• ricrea le destinazioni
• recupera la lista di “durable subscriptions” per ogni topic
• recupera la lista dei messaggi
• recupera la lista di acknowledge per ogni messaggio
È possibile configurare ActiveMQ perchè gestisca la persistenza tramite file (AMQ
message store) o tramite database esterno al provider JMS.
È stata scelta quest ultima opzione perche ha come vantaggio un più facile recupero e
interpretazione dei dati rispetto al caso in cui si utilizzi l’ AMQ message store, un
sistema di gestione della persistenza basato su file utilizzato di default da ActiveMQ..
Le operazioni di accesso e scrittura su un DB sono sicuramente più pesanti dal punto di
vista computazionale, ma questo approccio è sensato perchè la nostra applicazione non ha
requisiti particolari di high performance. All’ avvio il broker creerà automaticamente
due tabelle, ACTIVEMQ_ACKS e ACTIVEMQ_MSGS: la prima tabella mantiene in
memoria informazioni relative ai subscribers e informazioni relative ai messaggi
acknowledged, la seconda contiene al suo interno informazioni relative ai messsaggi.
2. High Availability e fault tolerance
Le funzionalità finora introdotte non sono sufficienti qualora al sistema vengano richieste
anche caratteristiche di affidabilità ed alta disponibilità.
Nonostante siano stati resi persistenti i messaggi e siano state create sottoscrizioni
durevoli, il provider JMS rappresenta un punto critico per l’ applicazione in quanto un
suo eventuale crash non garantisce la continuità del servizio: in tal eventualità bisogna
aspettare un suo riavvio prima che i messaggi possano essere consegnati nuovamente.
ActiveMQ nella versione 5.1 mette a disposizione una funzionalità master/slave per
garantire alta disponibilita e tolleranza ai guasti: l’ idea che guida questa funzionalità è
che i messaggi vengano replicati su dei broker slave di modo che, in caso di failure
hardware sulla macchina del master, si abbia immediato failover sullo slave senza perdita
di messaggi. Utilizzando un database condiviso e JDBC come connettore è possibile
adottare una configurazione master/slave eseguendo tanti broker quanti si ritengono
opportuni, come mostrato nel seguente diagramma.
Se il master perde la connessione al database o perde il lock esclusivo allora termina
immediatamente l’esecuzione. Quando il master termina l’ esecuzione o fallisce, uno
degli altri slave s’impadronisce del lock. I client perdono la connessione al master che si è
fermato e il transport failover cerca di riconnetterli ai broker disponibili, uno dei quali
diventa il nuovo master.
Quando si riavvia il broker che aveva fallito questo riparte come slave, aspettando di
impadronirsi del lock per diventare il master.
In sostanza uno slave fornisce un broker hot stand by che sarà sempre sincronizzato,
pronto a prendere posto se il master s’interrompe in seguito ad hardware failure.
Per la nostra applicazione si è scelto di utilizzare un cluster di due broker per ottenere
affidabilita e contenere i costi del sistema. Per configurare il cluster è sufficiente
modificare i file di configurazione activemq.xml in ciascuna macchina del cluster come
segue:
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds"/>
</persistenceAdapter>
in modo da istruire i broker ad usare unicamente JDBC come data source.
I client utilizzano il layer di trasporto Failover di ActiveMQ per collegarsi a uno dei
broker : la sintassi di configurazione del Transport Failover permette di specificare un
qualsiasi numero di URI. Il layer di trasporto failover sceglie casualmente uno degli URI
e cerca di stabilire una connesione con esso: se ciò non avviene o se la connessione
fallisce, una nuova connessione viene stabilita con uno degli altri URI.
Dunque i client utilizzano la seguente stringa per connettersi ai broker disponibili:
failover:(tcp://broker1:61616,tcp://broker2)
dove broker1 e broker2 sono i nomi o gli indirizzi IP delle macchine su cui vogliamo
eseguire i broker.
3. Clustered JDBC
Lo svantaggio di una configurazione dei broker JDBC master/slave, come evidenzia il
diagramma precedente, risiede nel fatto che si fa affidamento su un database come unico
sistema di gestione della persistenza, e si ha pertanto un singolo punto di fallimento: in
caso di hardware failure nella macchina su cui gira il database si perderebbero tutti i
messaggi. Per evitare questo inconveniente nella nostra applicazione si sfrutta il concetto
di RAIDb, Redundant Array of Inexpensive Databases.
Uno degli obiettivi di RAIDb è quello di fornire a basso costo tolleranza ai guasti e
prestazioni migliori di quelle di un singolo database, combinando molteplici istanze di
database in una matrice di database. RAIDb-1 è una replica completa del database su
ogni nodo del cluster e consente di accedere in maniera trasparente ad un cluster di db con
l’astrazione di un unico db.
Nonostante una replica competa vada a discapito di un rallentamento nelle operazioni di
scrittura (UPDATE, INSERT, DELETE), si è deciso comunque di effettuare questa scelta,
considerato che l’ applicazione non effettua scritture su db, se non nei casi in cui il
provider JMS scrive nelle tabelle ACTIVEMQ_ACKS e ACTIVEMQ_MSGS.
Anche se ciò può effettivamente avvenire con una frequenza elevata a seconda del
numero di messaggi nel topic, le prestazioni non subiscono un degradamento
significativo, dal momento che si è ritenuto sufficiente un numero di due backends per
garantire affidabilità per cui le scritture devono essere trasmesse solo a due nodi.
Per ottenere una configurazione RAIDb-1, si è deciso di utilizzare una tecnologia Java
open source: Sequoia 2.10.10.
Sequoia è un middleware open source che permette a qualsiasi applicativo di accedere in
maniera trasparente ad un cluster di database tramite JDBC. Il driver Sequoia è un
generico driver JDBC che sostituisce il driver JDBC specifico utilizzato dal client.
Il driver Sequoia inoltra le interrogazioni SQL attraverso RMI al controllore Sequoia e ne
riceve i corrispondenti risultati. Il client deve solo conoscere su quale nodo gira il
controllore ed il nome del database virtuale cui accedere.
Grazie a Sequoia si può settare la persistenza nel file XML di ogni broker facendo
riferimento a un singolo database astratto con il seguente codice:
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#sequoia-ds" />
</persistenceAdapter>
<!-- Sequoia DataSource -->
<bean id="sequoia-ds" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName"
value="org.continuent.sequoia.driver.Driver"/>
<property name="url"
value="jdbc:sequoia://host1/activemq?relaxAutoCommit=true"/>
...
</bean>
Il database utilizzato viene chiamato activemq perchè di default ActiveMQ crea le tabelle
ACTIVEMQ_ACKS e ACTIVEMQ_MSGS all interno di questo database; esso è
solamente un’astrazione di un database in quanto fa riferimento a due backend reali posti
su due macchine diverse (activemqDb1 e activemqDb2).
Per ottenere questa astrazione è sufficiente modificare il file XML usato dal controllore
Sequoia (controller.xml) con la seguente stringa, in maniera analoga per ogni nodo:
<DatabaseBackend name=”node1”
driver="org.gjt.mm.mysql.Driver"
url=”jdbc:mysql://localhost/activemqDb1”
connectionTestStatement=”select 1”>
È necessario settare in questo file username e password usati da MySql per accedere al db
su ciascun nodo e impostare il nome del database vrtuale con username e password per
accedervi.
All’ interno del db activemq sono state inserite anche la tabella auth_table, contenente i
campi bidderName (chiave primaria) e bidderPassword, e la tabella lots contenente i
campi lotId (chiave primaria), titolo e prezzo.
Servizio di login
Il nucleo centrale del servizio di login è costituito da due code unidirezionali, loginQueue
e confirmQueue, e da due attori, ovvero il bidder che si vuole autenticare e un servizio
autenticatore lato server.
Similmente al caso del topic anche per il servizio di login le applicazioni conivolte
ricevono i messaggi dalle destinazioni in modo asincrono. All’ atto del login il bidder
invia nella loginQueue un messaggio chiamato LogIn, cioèun oggetto TextMessage che
incapsula come stringa Java un documento XML di questo tipo:
<LiveAuctionMessage>
<Action> LogIn </Action>
<BidderName> Andrea </BidderName>
<BidderPassword> xxxxx </BidderPassword>
</LiveAuctionMessage>
Dal lato server deve essere attivo un servizio di autenticazione che implementa una classe
receiver: alla ricezione del messaggio di LogIn nella loginQueue in maniera asincrona
vengono estratti i dati di login dal messaggio e confrontati con quelli memorizzati nella
tabella auth_table (dove si suppone siano memorizzati i dati degli utenti che si sono
precedentemente registrati all’ asta via e-mail).
Il servizio di autenticazione per ogni messaggio di LogIn inserito nella coda loginQueue
invia nella confirmQueue un messaggio chiamato Confirm di questo tipo:
<LiveAuctionMessage>
<Action> Confirm </Action>
<UserName> Andrea </UserName>
<Token> true </Token>
</LiveAuctionMessage>
Analogamente il bidder, all’atto della ricezione di un messaggio di Confirm, legge il
valore del token di tipo boolean e se questo corrisponde a true chiude il frame di login
per aprire quello da cui il bidder puo partecipare all’ asta.
Si è deciso di impostare un TimeToLive per il messaggi di LogIn e Confirm per evitare
che, in caso il servizio di autenticazione non sia attivo a causa di una failure, rimangano
messaggi inevasi nelle code.
Packages e classi
Il software è organizzato in quattro packages.
Il package liveauction.common comune a tutte le applicazioni contiene classi di utilità
generica come DBConnection che implementa i metodi per connettersi al database e
leggerne i dati, e la classe XML_log che salva i messaggi su dei file XML, utilizzati per
effettuare il parsing e come file di log per gli acquirenti e il battittore.
I package liveauction.bidder e liveauction.admin realizzano le applicazioni bidder e
admin e contengono classi che implementano la logica di pubblicazione nel topic, di
sottoscrizione e ricezione dei messaggi da questo (PublisherLogic, Publisher,
Subscriber).
I package liveauction.bidder e liveauction.authenticator contengono anche le classi che
implementano la logica di invio e ricezione dei messaggi nelle code (SenderLogic,
Sender, Receiver).
Le classi MessageService e ParserXML sono comuni a tutti i packages delle tre
applicazioni. La classe MessageService costruisce i messaggi e li pubblica nei topic o li
invia alle code. ParserXML provvede ad elaborare i documenti XML. per permetterne l’
estrazione dei dati d’ interesse.
Conclusioni e sviluppi futuri
L’ infrastruttura realizzata offre un sistema robusto e a basso costo per gestire aste in
tempo reale. È stato realizzato un prototipo della piattaforma e, a causa della mancanza
di una rete su cui poter lavorare, sono stati effettuati test solo su tre macchine organizzate
con un cluster di due broker in configurazione master/slave, un cluster di due database
replicati su due delle macchine disponibili, e quattro bidder loggati sulle tre macchine a
disposizione ( tre di questi con clientId per la sottoscrizione al topic uguale al numero IP
della macchina, e il quarto con clientID uguale a null). Sono stati simulati diversi scenari
e possibili guasti e i risultati hanno dimostrato un buon grado di affidabilità e un ottimo
funzionamento dell’ architettura progettata.
Si è osservato un leggero ritardo (variabile, dell’ ordine di qualche secondo) nella
connesione al database e quindi nell’apertura del primo lotto.
Ciò èdovuto al fatto che si è scelto di utilizzaree come sistema di gestione della
persistenza un database, rinunciando agli high perfourmance journal, ossia file utilizzati
come storage da ActiveMQ aventi funzionalità simili a quelle di un database, ma piu
performanti. Inoltre un’ organizzazione RAIDb-1 del database rallenta la connessione al
db e le operazioni di scrittura, come osservato precedentemente. Questi inconvenienti non
rappresentano un grave problema e non precludono il funzionamento dell’ infrastruttura,
dal momento che comportano solo un ritardo nell’ apertura del primo lotto, per cui gli
acquirenti semplicemente attenderanno pochi secondi prima dell’ inizo dell’ asta.
Tuttavia si possono migliorare le perfomance se si hanno a disposizione file system di
rete come i file system SAN (Storage Area Netwrks) che sono file system
simultaneamente montati du diverse macchine. Utilizzando come sistema di gestione
della persistenza file system di rete si possono migliorare nettamente le performance, dal
momento che le operazioni su file sono sicuramente meno pesanti dal punto di vista
computaziionale rispetto a quelle su db.
In questo modo però si aumentano anche i costi del sistema, per cui la soluzione
progettata rappresenta un buon compromesso tra performance e costi.
Considerato che i messaggi rappresentano transazioni di denaro, è possibile inoltre
rafforzare l’applicazione introducendo livelli di sicurezza sia all’ interno dei messaggi
sotto forma di funzioni hash, sia per quanto riguarda il protocollo di comunicazione (ad
esempio utilizzando SSL). Possibili miglioramenti possono riguardare anche il servizio
di autenticazione che si può pensare di replicare per garantire disponibilità: nella
soluzione proposta, in caso di caduta dell’ autenticatore, il client deve aspettare il riavvio
del servizio e riprovare ad autenticarsi più tardi.
Dal momento che l’applicazione admin nasce per affiancare un’asta in sala, si può far in
modo che l’ admin possa aggiornare i prezzi provenienti dalla sala, cioè possa a sua volta
fare offerte pubblicando a sua volta messaggi di Bid nel topic.