WebSphere 7.0 e Cache Distribuita: l’alter ego di EJB 3.1 @Singleton ?

La piattaforma Java EE 6 ha introdotto notevoli salti di qualità per quanto riguarda lo strato di persistenza e quello web. Siamo passati infatti da JPA 1.0 e JSF 1.2 direttamente a JPA 2.0 e JSF 2.0. Per quanto riguarda lo strato di logica di business invece abbiamo avuto un piccolo incremento di sottoversione (3.0 -> 3.1), d’altro canto il grande salto era già stato fatto dalla Java EE 5 in questo senso. EJB 3.1 ci riserva però una piacevole sorpresa, ovvero un nuovo tipo di EJB chiamato Singleton, di cui abbiamo già parlato in un post precedente. Per chi però lavora con WebSphere 7.0 (WAS), senza feature pack particolari, ancora non può accedere ad un bean di questo tipo, ma può girare intorno al problema sfruttando in modo opportuno la Cache Distribuita che l’Application Server mette a disposizione. Vediamo di che si tratta.

Singleton in cluster

C’è chi ritiene che il Singleton sia un antipattern, il male assoluto, e chi invece lo inzuppa nel latte a colazione. Come sempre, in medio stat veritas (o come si dice dalle mie parti il troppo stroppia): se usato con accortezza, il Singleton è un ottimo strumento, per esempio come parser di file di configurazione usato in sola lettura. A parte tutto, i problemi insorgono quando si ha a che fare con un Singleton in cluster, essendo infatti statico ed inizializzato dalla JVM, esso verrà replicato su ogni noto del cluster, perdendo la sua caratteristica di essere l’unica istanza all’interno dell’applicazione. EJB 3.1 risolve il problema introducendo quindi un nuovo tipo di EJB. WAS 7.0 invece, essendo compliant Java EE 5, non ha ancora questo nuovo tipo di EJB. Sfruttando però la Cache Distribuita dell’Application Server è possibile aggirare il problema.

Data Replication Service

WebSphere dispone infatti di un sistema di cache dinamica che memorizza l’output delle servlet, dei servizi Web e dei comandi WebSphere per migliorare le prestazioni delle applicazioni. Utilizzando questa cache è possibile memorizzare e condividere oggetti Java in un ambiente clusterizzato.
Tramite un servizio denominato Data Replication Service (DRS), la cache istanziata dal WAS in ogni nodo viene tenuta sincronizzata, ovvero replicata, l’una con l’altra in modo da avere uno strato di informazioni uniche in tutto il cluster, come mostrato in figura:

Schema Cache Distribuita in cluster

Cache Distribuita: configurare il servizio

Come tutte le risorse degli Application Server, se si intende utilizzare questo servizio, deve essere prima opportunamente configurato.

Esistono 3 modalità di configurazione:

  1. configurazione dal pannello di amministrazione del WAS;
  2. file di configurazione nell’EAR (distributedmap.properties);
  3. dichiarazione di una resource-ref nei descrittori di distribuzione del modulo web (file web.xml e ibm-web-bnd.xmi)

IBM consiglia il primo approccio, che è l’unico che affronteremo. Per completezza, rimandiamo alla documentazione IBM per approfondire le altre modalità.

Dal pannello di amministrazione del WAS, andare su Resources -> Cache instances -> Object cache instances e cliccare su New.

Pannello di configurazione cache distribuita

Completare i campi obbligatori. Per convenzione il campo Name corrisponde all’ultima parte del campo JNDI name: IBM consiglia di inserire i servizi di cache nel percorso JNDI services/cache/, per cui, se il nome inserito è myCache, il corrispettivo percorso JNDI sarà services/cache/myCache. Gli altri valori possono essere lasciati con i valori di default.

Cache Distribuita: usare il servizio

Una volta configurato, come si presenta la relativa API di accesso al servizio? Come recuperare il servizio dal server?

L’interfaccia del servizio

La cache è implementata come una mappa e gestita dall’interfaccia DistributedMap: estendendo java.utils.Map, il suo utilizzo non differisce da quello di una classica mappa Java. A questa però aggiunge alcuni metodi che permettono di accedere a funzionalità specifiche come:

  • inserimento “avanzato” in cui, oltre a chiave/valore, si può specificare:
    • priorità di un elemento (più è alta, più è importante in caso intervengano politiche di gestione overflow che ripuliscono la cache);
    • tempo di vita di un elemento nella cache (in secondi);
    • politica di condivisione nella cache.
  • listener sul cambiamento degli elementi nella mappa;
  • listener sull’eliminazione di un elemento nel caso di:
    • eliminazione esplicita dell’utente;
    • timeout (se impostato in creazione);
    • eliminazione di un elemento vecchio in caso di cache piena.

Recuperare il servizio dal server

Con un semplice lookup da JNDI è possibile recuperare l’istanza della cache come definita dal pannello di amministrazione di WAS:

InitialContext context = new InitialContext();
DistributedMap myCache = (DistributedMap) context.lookup("services/cache/myCache");

Conclusioni

L’utilizzo di uno strumento come la mappa distribuita può essere molto utile quando si vuole condividere oggetti (ovviamente serializzabili) in ambiente cluster tra le varie JVM. C’è da tenere presente però che una risorsa di questo tipo non è specifica di una applicazione, ma è un vero e proprio servizio messo a disposizione dal WAS: questo implica che se essa viene usata da una applicazione per aggiungere parametri alla mappa, l’applicazione stessa ha la responsabilità di implementare la logica di eliminazione dei parametri inseriti, altrimenti questi permangono in memoria. In questo senso, la mappa dispone di un metodo di inserimento che permette di specificare anche il tempo di vita di un valore in cache, in modo da non preoccuparsi di gestirne l’eliminazione. Inoltre, dato che la mappa al momento (come dichiara IBM) non è soggetta a nessun controllo di sicurezza, può essere raggiunta e usata (sia in lettura che in scrittura) da qualsiasi applicazione deployata sul cluster, quindi occhio a come viene usata!

Andrea Como

Sono un software engineer focalizzato nella progettazione e sviluppo di applicazioni web in Java. Presso OmniaGroup ricopro il ruolo di Tech Leader sulle tecnologie legate alla piattaforma Java EE 5 (come WebSphere 7.0, EJB3, JPA 1 (EclipseLink), JSF 1.2 (Mojarra) e RichFaces 3) e Java EE 6 con JBoss AS 7, in particolare di CDI, JAX-RS, nonché di EJB 3.1, JPA2, JSF2 e RichFaces 4. Al momento mi occupo di ECM, in particolar modo sulla customizzazione di Alfresco 4 e sulla sua installazione con tecnologie da devops come Vagrant e Chef. In passato ho lavorato con la piattaforma alternativa alla enterprise per lo sviluppo web: Java SE 6, Tomcat 6, Hibernate 3 e Spring 2.5. Nei ritagli di tempo sviluppo siti web in PHP e ASP. Per maggiori informazioni consulta il mio curriculum pubblico. Follow me on Twitter - LinkedIn profile - Google+