A Reliable Message Oriented Middleware based on Publish and Subscribe paradigm Mirko Matoffi a.a. 2003/2004
Message Oriented Middleware Middleware basato sullo scambio di messaggi caratterizzato da: forte disaccoppiamento tra le entità in gioco asincronicità persistenza supporto naturale alla comunicazione many-to-many altamente scalabile Tipicamente due tipologie di comunicazione: Message Queuing modello point-to-point Publish and Subscribe modello many-to-many (topic-based o content-based)
Connection Session Connection Factory Publisher Subscriber Topic crea invia riceve Architettura Logica (JMS)
Publisher Client Subscriber Client Topic Publish message TopicProxy Subcribe / Unsubscribe Message delivery DB Connection Factory Client getConnection()
Procedura di amministrazione NAMESPACE Topic1 Topic2 Topic3 Connection Factory 1: bind Client 2: lookup Message Service Provider 3: connection Sistema di Nomi
Server Attivo Topic1 Topic2 CF Client1 Client2 Server Passivo Stato Server Attivo Canale di Coordinazione Canale di HeartBeating DB Configurazione Cluster
Server Attivo Topic1 Topic2 CF Client1 Client2 Server Passivo Canale di Coordinazione Canale di HeartBeating DB Failure Topic1 Topic2 CF Failover
Canale di coordinamento Connessione attiva tra il server primario ed il server in standby attraverso la quale vengono inviate le informazioni di stato in modo da mantenere aggiornato il server secondario Un Topic!?!
Infrastruttura di Heartbeat (1) necessaria per monitorare il corretto funzionamento di una risorsa basata sullinvio di un messaggio di Alive inviati con una predeterminata frequenza da un apposito componente ad indicare il che tutto è ok in caso di mancata ricezione del messaggio per un certo periodo, è necessario informare un sistema di recovery che dovrà assumere le adeguate contromisure necessita di un canale di comunicazione Un Topic!!?
Infrastruttura di Heartbeat (2) Quella descritta in precedenza è unarchitettura del tutto generale che può essere utilizzata da qualunque applicazione necessiti di una simile funzionalità Nel nostro sistema questa infrastruttura viene realizzata imponendo al server in standby di registrarsi presso lapposito Topic LActivation Procedure non fa altro che caricare lo stato precedentemente salvato in modo da preparare il nuovo server a rispondere alle richieste degli utenti Quanti Server in stand-by?
Applicazione Server attiva Affinchè larchitettura Cluster progettata funzioni, allo startup il processo active server deve: 1. creare e registrare lHeartbeatTopic 2. creare un publisher relativo a questo topic ed impostarlo correttamente per linvio di messaggi di Im Alive 3. creare un oggetto HeartbeatPublisher che, utilizzando il publisher appena creato, invii i messaggi con una certa frequenza 4. creare e registrare un CoordinationTopic 5. creare un publisher associato ad esso 6. inviare tramite questo publisher un messaggio ogni volta cambia lo stato sul server inviando le nuove informazioni
Applicazione Server Passiva Affinchè larchitettura Cluster progettata funzioni, allo startup il processo standby server deve: 1. creare una connessione con il server attivo tramite la ConnectionFactory 2. creare una sessione con lHeartbeatTopic 3. creare un Subscriber per ricevere i messaggi provenienti dal topic in questione 4. creare un HeartbeatSubscriber che controlli la frequenza di arrivo dei messaggi e, in caso di anomalia, invochi la procedura di Recovery 5. creare una sessione con per il CoordinationTopic 6. creare un Subscriber per ricevere i messaggi provenienti da esso
Struttura di un messaggio Header Destinazione: nome del Topic MessageID: identificativo univoco di un messaggio CorrelationID: id del messaggio di riferimento DeliveryMode: Persistente o Non-Persistente Timestamp: ora di invio Expiration: istante di fine validità Priority: priorità del messaggio (da 0 a 9) MessageProperties insieme di proprietà di tipo nome-valore possibilità di inviare oggetti possiblità di fungere da selettore di un messaggio Body Testo del messaggio Oggetto java.lang.String compatibile con XML
Stringa Messaggio Publisher Session Connection Send Message to Topic Client Application Topic1 Topic2 CF Lookup topic Name Registry Topic Send Message Server Application Invio di un Messaggio
Client Application Server Application Topic Subscriber TopicProxy New Message Message IMessageObserver Message Ricezione di un messaggio
… quale connessione? Larchitettura ed i protocolli finora esposti valgono per qualunque tipo di connessione si voglia utilizzare; loggetto responsabile che incapsula tutta la logica di connessione è loggetto Connection Possibilità di fornire allutente più tipologie di connessione per inviare un messaggio aumentando così laffidabilità del sistema
Java RMI Con questa tecnologia loggetto Connection non deve far altro che effettuare un lookup sul Registry per ritrovare il riferimento remoto al Topic interessato ed invocare lappropriato metodo (interfaccia ITopicRMI) Il ClientConnectionManager dovrà invece recuperare il riferimento alloggetto ConnectionFactory per poter poi creare un oggetto Connection tramite lapposito metodo (interfaccia IConnectionFactoryRMI)
IConnectionFactoryRMI e ITopicRMI public interface IConnectionFactoryRMI extends Remote { public Connection createConnection(String userName, String password) throws RemoteException; } public interface ITopicRMI extends Remote { public boolean publish(Message message, String user) throws RemoteException; public boolean removeSubscriber(String user) throws RemoteException; public boolean subscribe(String user, IClientRMI client) throws RemoteException; public boolean setImOnLine(String user, IClientRMI client) throws RemoteException; }
RMI Callback (IClientRMI) Come mostrato precedentemente, la comunicazione non avviene soltanto dal Client verso il Server, ma anche nel verso opposto. In particolare il TopicProxy dovrà utilizzare il riferimento remoto fornito dal Subscriber in fase di sottoscrizione per passargli il nuovo messaggio arrivato public interface IClientRMI extends Remote { public boolean newMessage(Message m) throws RemoteException; public String getClientID() throws RemoteException; }
La classe Subscriber public class Subscriber extends UnicastRemoteObject implements IClientRMI, ILocalMessageRecipient{ public boolean newMessage(Message m) throws java.rmi.RemoteException { messages.addElement(m); for(int i=0; i<observers.size(); i++){ ((IMessageObserver)observers.get(i)).onMessage(m); } return true; } public void attach(IMessageObserver mo){ observers.addElement(mo); } public void detach(IMessageObserver mo){ observers.removeElement(mo); } … }
La classe Connection Responsabile della comunicazione tra Client e Server Effettua il lookup Salva localmente i riferimenti ai topic utilizzati in modo da non appesantire il Registry Deve gestire un eventuale failover del Server In caso di errore di connessione si rivolge al ClientConnectionManager chiedendo di trovare la nuova locazione del Server e di comunicargliela Gestione del refresh delle cache degli indirizzi a carico del Client
Tool di amministrazione
Possibili sviluppi Introduzione di un sistema di discovery Uso di SOAP per una maggiore interoperabilità Implementazione di politiche di sicurezza Implementazione del Message Queueing Sottoscrizioni di tipo Topic-based Rendere il middleware adattativo