Con il rapido sviluppo delle tecnologie collegate ad AJAX, le modalità di interazione con il Web Server stanno cambiando. In particolare, cresce il numero di richieste inviate dal client, necessarie per la dinamicità propria di AJAX. Le Servlet asincrone potranno essere una risposta?
L‘idea nasce dal blog di Greg Wilkins, autore fin dal 1995 di software Open Source. È in quell‘anno
infatti che inizia lo sviluppo del server HTTP Jetty e del relativo Servlet Container. Ora Jetty è
parte di CodeHaus (http://www.codehaus.org/). Greg ha contribuito inoltre a JBoss e ad Apache
Geronimo. Come esperto di tecnologie Web e Servlet in particolare, ha voluto condividere le sue idee
sull‘evoluzione che dovrebbero avere le servlet, dopo la finalizzazione della versione corrente, la
2.5.
Il problema scatenante è il nuovo modello di chiamata a “cometa”, utilizzato dalla nuova generazione
di applicazioni Web che utilizzano AJAX. In origine, infatti le applicazioni AJAX utilizzavano un
modello di tipo “polling”: il client, a intervalli regolari, inviava richieste al server allo scopo di
mantenere aggiornata e/o validata l‘interfaccia utente. Con lo stile a “cometa” il client apre una
connessione HTTP, che viene lasciata aperta dal Web Server. In questo modo il server ha la possibilità
di inviare informazioni al client in modalità push. In sostanza, si utilizzano connessioni HTTP long-
lived, a lunga durata. Questo è un modo più efficiente di utilizzare le risorse, ma anche questo
modello non è privo di problemi. L‘analogia con la cometa risiede nel fatto che la prima richiesta può
essere considerata come la testa di una cometa e la sua scia rappresenta il tempo in cui la
connessione HTTP rimane aperta.
Le novità proposte
I casi d‘uso che Greg profila, soprattuto in merito allo stile di programmazione a “cometa”, sono i
seguenti:
- input non bloccante. L‘abilità di ricevere dati da un client senza bloccare l‘esecuzione se i dati arrivano lentamente. Effettivamente, questo aspetto non è centrale per l‘API asincrona, visto che la maggior parte delle richieste perviene in un singolo pacchetto. Inoltre la gestione può essere postposta fino all‘arrivo del primo pacchetto contenente dati effettivi. L‘obiettivo sarebbe comunque l‘evoluzione delle API delle servlet verso applicazioni che non debbano implementare alcun input/output.
- output non bloccante. È la caratteristica di inviare dati al client senza bloccare l‘esecuzione se il client o la rete sono lenti. Sebbene la necessità di output asincrono è molto maggiore rispetto alla necessità dell‘input asincrono, Greg non ritiene neanche questo un elemento essenziale. Grandi buffer possono permettere al Servlet Container di inviare la maggior parte delle risposte in modo asincrono. Inoltre, per risposte di dimensioni ragguardevoli sarebbe meglio evitare del tutto che il codice dell‘applicazione gestisca l‘input/output.
- ritardare la gestione della richiesta. Lo stile “cometa” delle Web Application AJAX possono richiedere che la gestione di una richiesta venga ritardata fino a quando non avviene un timeout o un qualche tipo di evento. Il ritardare la risposta alle richieste è utile anche in quei casi in cui sia necessario recuperare una risorsa remota o lenta da caricare prima di poter servire la richiesta o in qui casi in cui sia necessario temporeggiare per evitare troppi accessi simultanei. Attualmente l‘unico modo per supportare questo punto, e che sia anche conforme alle specifiche, è di attendere all‘interno della servlet. Questo però comporta un consumo di risorse e di thread.
- ritardare la chiusura della risposta. Applicazioni Web AJAX che utilizzano lo stile cometa potrebbero richiedere che una risposta sia lasciata aperta per permettere l‘invio di dati addizionali quando avviene un evento asincrono. Anche in questo caso, l‘unico modo standard in cui si può fare ora è di attendere all‘interno della servlet, consumando un thread e altre risorse.
- gestione del codice 100 (Continua). Un client potrebbe richiedere un handshake dal server prima di inviare il corpo della richiesta. Se questo viene inviata automaticamente dal contenitore diventa impossibile utilizzare il codice di ritorno 100. Se l‘applicazione è in grado di decidere se inviare un codice 100, un‘API asincrona potrebbe evitare che un thread venga consumato durante il ritorno al client.
Tutti questi casi possono essere riassunti come: “alcune volte è solo necessario fermarsi ad attendere
qualcosa”, sapendo che un‘attesa all‘interno del metodo Servlet.service() è costoso, per i seguenti
motivi:
- è necessario un thread.
- Se l‘input/output è iniziato sono necessari i relativi buffer.
- Se sono stati ottenuti i Reader/Writer, sono necessari i relativi converititori di caratteri.
- La sessione non può essere passivata.
- Tutto quanto allocato dalla catena dei filtri servlet deve essere mantenuto.
Le soluzioni
Ad oggi esistono alcune implementazioni che cercano di affrontare questo problema:
- Jetty ha il meccanismo della Continuazione, studiato per le applicazioni comet;
- BEA ha un meccanismo di risposte future;
- Glassfish ha un layer NIO estensibile per I/O asincrono al di sotto del modello delle servlet;
- Gli sviluppatori di Tomcat hanno appena iniziato lo sviluppo al supporto di applicazioni
comet.
Greg rileva come la cosa ironica è che, mentre la versione 2.5 delle Servlet risolve moli problemi di
portabilità , AJAX ne sta introducendo di nuovi. Ed effettivamente la versione 2.5 non ha portato molte
novità , ma tante chiarificazioni orientate alla portabilità . AJAX pone delle nuove problematiche che
il JCP dovrà affrontare.
Non è ancora chiaro come si possa standardizzare una soluzione, ma Greg rileva cosa NON dovrebbe
essere:
- una API su una servlet specifica. Nel momento in cui il Servlet Container ha identificato la specifica servlet da invocare, molte delle operazioni collegate sono state svolte. Inoltre, siccome i filtri e i dispatcher sono in grado di redirigere la richiesta, qualsiasi API asincrona strettamente legata a una servlet dovrebbe seguire lo stesso percorso.
- Basata sulla tecnologia Continuations di Jetty. Sebbene questa sia una utile astrazione è necessaria una soluzione più a basso livello in grado di offrire una maggiore efficienza e permettere ulteriori funzionalità .
- L‘esposizione di canali o in generale API NIO al programmatore della servlet. Questi dettagli di implementazione dovrebbero essere nascosti all‘utilizzatore; inoltre, in taluni casi si potrebbero impiegare tecnologie diverse da NIO.
La soluzione su cui sta lavorando Greg è diversa. Si basa su un oggetto coordinatore che può essere
mappato a percorsi URL proprio come i filtri e le servlet. Il coordinatore dovrebbe essere richiamato
dal contenitore in risposta a eventi asincroni e si dovrebbe occupare del coordinamento delle chiamate
sincrone ai servizi.
Conclusioni
Se l‘idea di Greg si dimostrerà rispondente alle nuove sfide che pone lo stile di programmazione a
“cometa”, ne verrà implementato un prototipo in Jetty 6, e da qui potrebbe passare al JCP, per essere
standardizzato.
Bibliografia
[1] http://www.theserverside.com/news/thread.tss?thread_id=40560
[2] http://www.mortbay.com/MB/log/gregw/?permalink=asyncServlets.html
[4] http://docs.codehaus.org/display/JETTY/Continuations
[5] http://blogs.pathf.com/agileajax/2006/05/comet_socket_hu.html
[6] http://alex.dojotoolkit.org/?p=545
[7] http://www.irishdev.com/NewsArticle.aspx?id=2166