17 giu 2011

Un DAL apolide (seconda parte)

Proseguiamo l'analisi sull'approccio migliore per la scrittura di un DAL che risponda a richieste di più client in contemporanea (eventualmente smistate su più database):

Consideriamo per ora l'ipotesi semplificativa di DAL che debba connettersi ad un solo db, con un unica stringa di connessione. Scartiamo l'idea di aprire una connessione unica all'avvio dell'applicazione, perché stiamo parlando di architetture distribuite, in cui le richieste di servizio non sono contigue: non vogliamo occupare una risorsa del db se non ne facciamo uso: apriremo una connessione solo quando un client ci chiederà un servizio.

Si osservi che, per il nostro DAL, il servizio richiesto dal client coincide con una funzione pubblica.

Dobbiamo aprire la connessione all'avvio della funzione pubblica e chiuderla alla fine, prima di restituire al client la risposta.

Come viene effettuata l'apertura della connessione? Tipicamente avremo una libreria di accesso allo specifico database, a cui chiederemo la connessione. Qui occorre operare una scelta: la libreria ci fornisce una nuova connessione creata apposta, oppure un puntatore ad un'unica connessione?

Nella prima figura immaginiamo che tre client invochino quasi contemporaneamente tre funzioni pubbliche, e che il DAL, per ogni funzione, richieda al database la connessione.

 Se l'architettura applicativa prevede che il database restituisca tre puntatori all'unica connessione, alla fine della funzione 3 la connessione verrà chiusa, le funzioni 1 e 2 che sono ancora in esecuzione corrono il rischio di effettuare operazioni su una connessione chiusa, generando errori.

Questo tipo di architettura può funzionare se e solo se esiste un solo client che invoca i metodi pubblici del DAL, e se li invoca in ordine strettamente seriale; qualsiasi parallelismo porterà certamente a condizioni d'errore. Quindi per un ambiente distribuito occorre operare una scelta diversa.

Nella seconda figura il database crea una nuova connessione per ognuna delle tre funzioni: questo ci permette di rispondere a più client in parallelo.

 Per quanto riguarda le performance, questo ultimo approccio naturalmente pone un dubbio: la continua creazione, apertura e chiusura di connessioni può essere un punto di attenzione a livello di prestazioni.

In ambiente .NET, le best practices ADO.NET suggeriscono di fare uso del connection pool, delegando al framework l'effettiva chiusura ed apertura delle connessioni: si veda http://msdn.microsoft.com/en-us/library/8xx3tyca(vs.71).aspx.

8 giu 2011

Campi blob in Oracle: come ottenerne la dimensione

Per ottenere la dimensione dell'oggetto contenuto in un campo BLOB di una tabella in Oracle, è sufficiente invocare una query di questo tipo:
SELECT dbms_lob.getlength(NOMECAMPOBLOB) FROM NOMETABELLA;

7 giu 2011

Compressione traffico IIS per RIA Services

Sviluppando applicazioni Silverlight / RIA, è possibile incorrere in un problema prestazionale in fase di rilascio: la quantità di traffico scambiato tra il servizio RIA ed il client silverlight (traffico che ha la forma di una serializzazione xml delle entities) appare piuttosto consistente: a titolo di esempio, una classica query di ricerca sul progetto CDS, che ritorna un numero di entities non superiore a 60 per riempire una griglia (paginata), può tranquillamente generare una risposta che raggiunge le dimensioni di 15-20 megabytes, con punte di quasi 30 megabytes.
la dimensione del traffico è dovuta alla procedura di serializzazione del servizio WCF, che trasforma le istanze delle classi in un nodo xml, accorpando tutte le informazioni per deserializzare il dato ottenendo l’istanza sul client silverlight; nel caso dei verbali le componenti della classe sono numerose, quindi è vasta la descrizione che viene inviata come traffico http (o https)
  • Una strada per ottenere una riduzione del traffico è quella di bypassare la serializzazione WCF e scriversi una routine ottimizzata che serializza le entities anziché su un xml, su un flusso di dati binari; occorre anche prevedere una routine di deserializzazione con la capacità di individuare errori nel flusso e richiederne la ritrasmissione. A monte della serializzazione "custom" e dopo la relativa deserializzazione devono rimanere valide le entities del RIA service, per continuare a giovarsi delle avanzate funzionalità introdotte con Silverlight 4. Questa strada appare immediatamente onerosa in termini di effort e rischiosa.
  • Un’altra strada è quella di continuare a giovarsi del servizio WCF per la serializzazione, e ridurre il traffico comprimendo a valle l’xml generato, usando un modulo di IIS (peraltro già attivo automaticamente in molte installazioni di IIS 7).
Questa ultima soluzione può sembrare un workaround, ma in realtà rappresenta la risposta migliore al problema del traffico: anche solo perché poggia su componenti software Microsoft già presenti sulle macchine, sicuramente testati e in produzione da anni.
Inoltre, questa soluzione ha il vantaggio di disassare il problema applicativo (già risolto nel caso CDS) dalle considerazioni prestazionali, permettendoci cioè di fare la cosa giusta: occuparci del design e della logica di business, senza deformare il modello per rispondere ad una problematica esterna, quale quella dell'efficienza trasmissiva, almeno un livello OSI sotto (ma probabilmente due) la nostra web-application.
Schematizziamo:
Problema: persistenza e gestione paradigma object oriented in ambiente distribuito.
Risposta: applicazione implementata sulle fondamenta di Silverlight 4 e RIA services
Problema: traffico elevato tra client e server
Risposta: compressione del solo traffico con procedure delegate ad IIS (lato server) e al browser (lato client)

Prova sul campo

Nelle prove effettuate il tempo di trasmissione di dati compressi è molto inferiore al corrispondente tempo per dati non compressi; la compressione è in carico al server, mentre l’operazione di decompressione è in carico al browser (i browser moderni gestiscono automaticamente questa funzionalità); il codice dell’applicazione non è stato toccato (non è stato nemmeno ripubblicato), ci siamo limitati a delegare ad IIS la compressione automatica dei dati xml in uscita dal servizio.
Abbiamo impostato IIS 6 sul server di test in modo che comprima automaticamente i contenuti, se nella GET del browser è impostato l’attributo

Accept-Encoding: gzip, deflateAccept-Encoding: gzip, deflate

I tempi (in connessione vpn) sono passati da 24 secondi a 5 secondi.

Link utili: