MokaByte 75 - Giugno 2003  
Il pattern Cache Management
di
Luca Dozio
In un'applicazione, per migliorare quelle che sono le performance di risposta ad una richiesta di servizio, è utile, in genere, prendere in considerazione la possibilità di effettuare un salva-taggio in memoria di una serie di dati (Value Object [VO]), che hanno determinate caratteristi-che di variabilità (bassa dinamicità), e che hanno un'alta frequenza di utilizzo.
L'articolo propone un'implementazione di una cache, partendo dall'esperienza del pattern di CacheManagement [CM].

La variazione alla proposta originale, vuole garantire flessibilità nella gestione delle politiche di cache ed un alto grado di disaccoppiamento nei confronti dell'applicazione in cui si innesta.
E' altresì vero, che un'attenta progettazione delle applicazioni enterprice, secondo i pattern più consolidati della letteratura J2EE [J2EE] e secondo le nuove specifiche Ejb, può garantire pre-stazioni eccellenti, prescindendo da un componente di cache studiato ad hoc.

 

Contesto
Il componente che l'articolo propone, si inserisce nel contesto di un'applicazione già esistente, con un design già consolidato. In questo contesto il componente di cache si occupa di migliora-re le performance di risposta ad alcune invocazioni, rendendo immediatamente disponibile l'oggetto di risposta alla richiesta, senza la necessità di elaborazioni ulteriori (chiamate remote, accesso a base di dati ed altro).

 

Intento
Il pattern realizza un tentativo di indirizzare il trattamento di oggetti che rappresentano i dati dell'applicazione, a cui il sistema accede con una certa frequenza e che hanno una variabilità temporale bassa. Tipicamente, si può pensare di conservare in una cache, i dati che rappresen-tano i comuni, le province, le regioni, oppure informazioni a bassa dinamicità legate alla strut-tura organizzativa, ed altro.

 

Motivazione
Il pattern disaccoppia l'effettiva implementazione dell'oggetto di cache, concentra in una clas-se la gestione delle politiche di caching, come il recupero della chiave per l'oggetto in cache, la valutazione dell'occupazione di memoria della cache, il rinfresco dei dati cached, e garantisce un'interfaccia unica e semplicemente integrabile nell'applicazione.

 

Struttura
Nella sua definizione originale [CM] il pattern ha la seguente rappresentazione:


Figura 1 - Class Diagram Originale Pattern CacheManagement
(clicca sull'immagine per ingrandire)

l'idea è quella di offrire una semplice interfaccia per effettuare il caching delle informazioni utili.
Spiegazione del funzionamento
Il ciclo di vita del componente pone a cavallo del life cicle dell'applicazione un'istanza del Ca-cheManager. L'invocazione viene fatta su tale istanza (fetchObejct(obj)) e si occupa di verifi-care se l'oggetto richiesto è presente nella Cache, oppure no. Se non è presente, si procede al reperimento dell'oggetto attraverso il normale ciclo di vita dell'applicazione.
Implementazione
Per garantire una migliore gestione di alcune caratteristiche del componente Cache ed inserirsi nel ciclo di vita di un framework già esistente, senza modificarne eccessivamente il funziona-mento, si è proceduto ad una leggera modifica del pattern.


Figura 2 - Class Diagram dell'implementazione proposta
(clicca sull'immagine per ingrandire)

La variazione inserita offre la possibilità di dichiarare la classe CacheManager come una To-pic ad una coda di messaging [JMS]. In generale si può vedere il CacheManager come un E-ventListener, che si mette in ascolto di eventi generati da una sorgente.
In tal modo le istanze di CacheManager che si registrano alla Topic potranno essere ammini-strate da un generatore di messaggi che funzionerà da administrator per la cache.
Inoltre disaccoppiare ulteriormente il mondo cache dal gestore di cache, permette di offrire di-verse implementazioni di Cache in maniera trasparente all'utilizzatore.


Figura 3
- Class Diagram dell'implementazione dell'oggetto Cache.
(clicca sull'immagine per ingrandire)

L'interfaccia rimane unica e nello specifico si offre una cache locale (wrapper di una Hashta-ble) e una Cache distribuita, che registra gli oggetti presso il JNDI Server.


Figura 4 - Sequence Diagram dell'uso del CacheManager.
(clicca sull'immagine per ingrandire)

L'implementazione del CacheManager gestisce il reperimento dei dati da una cache locale (migliori performance di risposta), o alternativamente da una cache distribuita su JNDI Sever (disponibilità del dato su più tier ed in cluster). Inotre gestisce le politiche di abilitazione della cache, di refresh degli oggetti in cache, ed altro, ricevendo i comandi di amministrazione dal generatore di eventi (nell'esempio specifico un subscriber JMS).

 

Un caso d'uso
Il design proposto effettua una di cache di oggetti, in modo indipendente dall'applicazione con cui viene interfacciato. La gestione proposta del management delle politiche di cache, presup-pone la presenza di un coda JMS. In pratica una minima variazione al codice del CacheMana-ger, lo rende indipendente da questo vincolo, e si può far pilotare il CacheManager da un Gene-ratore di Eventi generico.
Per contestualizzare l'uso del componente, si riporta come caso d'uso del CacheManager l'applicazione MokaPattern [MP]. In questo contesto, il componente di cache si pone a cavallo del request handler di richiesta dell'Account e memorizza l'Object Value che il business gene-ra (AccountOM). Non è sicuramente l'oggetto migliore da inserire nella cache, perché ha delle caratteristiche di dinamicità elevate, ma l'esempio ha lo scopo di dimostrare la possibilità di utilizzo del componente in modo indipendente dall'applicazione sviluppata.
L'archiettura del prototipo si modifica in questo modo:


Figura 5 - Architettura dell'esempio MokaPattern [MP] con l'inserimento del CacheManager
(clicca sull'immagine per ingrandire)

Esempio di codice estratto dall'hanlder:

public class AccountRequestHandler extends BaseRequestHandler {

public void execute(HttpServletRequest request,
                    HttpServletResponse response,
                    ServletContext context)
                    throws ServiceException{

AccountOM model = null;
CacheManager chm = new CacheManager();
try{
  //la chaive di ricerca e di memorizzazione è lo UserId
  model= (AccountOM)chm.fetchObject(userid);
}
catch(NotFoundObjectException nfoe){
  proxy = MvcFactoryBusinessDelegate.getBusinessDelegate(
          this.getClass().getName(),userid);
  model = ((MvcBusinessDelegateImpl)proxy).getAccount();
  chm.putObject(userid,model);
}
...


Per invocazioni successive il valore dell'AccountOM è immediatamente disponibile. Il CacheManager ne verifica la presenza nella cache e lo restituisce all'elaborazione.
Inoltre è interessante verificare l'operatività del Subscriber di amministrazione, che scatena l'evento di REFRESH, che rinfresca gli oggetti dalla Cache.


Figura 6
- Client di amministrazione della Cache
(clicca sull'immagine per ingrandire)

 

Il client invia un TextMessage (l'evento) alle varie istanze di CacheManager registrate in To-pic, e nel metodo onMessage si processa l'evento.

public void onMessage(Message policyMsgEvent) {
try {
if (policyMsgEvent instanceof TextMessage) {
TextMessage txtMsg = (TextMessage) policyMsgEvent;
if (txtMsg.getText().trim().equalsIgnoreCase("DISABLE")) {
this.enable = false;
}
if (txtMsg.getText().trim().equalsIgnoreCase("ENABLE")) {
this.enable = true;
}
if (txtMsg.getText().trim().equalsIgnoreCase("REFRESH")) {
this.removeAll();
}
}
} catch (Exception e) {…. }

In questo caso, avendo rimosso l'oggetto dalla cache, il CacheManager rilancia una NotFoun-dObjectException e il ciclo di vita dell'applicazione prosegue normalmente, andando a recupe-rare sul business, l'object model richiesto.

 

Commenti
L'articolo ha messo in evidenza una possibilità di sviluppo della gestione della cache in un ar-chitettura distribuita. In quest'ottica una serie di verifiche potrebbero essere interessanti.
Si vuole stimolare l'attenzione del lettore su eventuali problematiche legate all'implementazione del JNDI Server e sulla gestione della cache in cluster, nonché l'ottimizzazione dell'amministrazione con la console JMS.
L'argomento è complesso e non del tutto affrontato dalla letteratura in genere. Il design J2EE dovrebbe prescindere da componenti di questo tipo, ma a volte risulta necessario giungere ad un compromesso che affronti la questione perfomance dell'applicazione.

.
Bibliografia
[VO] S.Rossini, L. Dozio - "J2EE Patterns - Il pattern value object", Mokabyte N.69 Dicembre 2002
[CM] Mark Grand:
Patterns in Java Volume 1: A Catalog of Reusable Design Patterns Illustrated with UML, second edition
[JMS] S.Rossini - "Java Message Service - La gestione dei messaggi in Java II parte: la prati-ca" ", Mokabyte N.61 Marzo 2002
[J2EE] Alur,Crupi,Malks :
Core J2EE Patterns - Best Practices and Design Strategies
[MP] S.Rossini, L. Dozio - "J2EE Patterns - Il pattern MVC", Mokabyte N.70 Gennaio 2003"

Risorse
Scarica gli esempi descritti nell'articolo

 

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it