La lettura è spassosa, leggera (c'è anche un accenno a Dungeons&Dragons!)
Affronta un tema che finora ho sempre sentito sottovalutato
dal team in cui lavoro, ovvero i problemi di deploy / integrazione tra sistemi.
Spesso infatti noto una grande attenzione alle problematiche di design, di test, di refactoring, di processo,
di stima etc... ma su questo punto si sorvola.
Ogni aspetto legato al deploy, quello architetturale, di security, di logging, di recovery plan etc.
non verrà mai richiesto esplicitamente da un cliente. Un esempio classico è un sistema con un front end
web-based di cui non si sa nulla circa il numero di connessioni che può gestire senza subire effetti collaterali.
Parte 1: Stabilità
Un carinissimo esempio catastrofico, causato da una eccezione Java non catturata.
La morale è che i bachi esistono (pure laddove si usa tdd :)) e sono imprevedibili :
"Bugs will happen. They cannot be eliminated, so they must be survived instead."
I loro effetti possono essere ridimensionati con opportune tecniche
o l'adozione di certi pattern: "A better question to ask is, "How do we
prevent bugs in one system from affecting everything else?" [...]
They cannot—must not—allow bugs to cause a chain of failures."
Una classica obiezione circa l'implementare pattern di stabilità è l'eventuale costo. Il ragionamento
usato per rispondere è ben formulato e conclude con una frase molto condivisibile:
"Good stability does not necessarily cost a lot. [...]
The amazing thing is that the highly stable design usually costs the
same to implement as the unstable one."
Segue della nomenclatura, forse la parte più interessante è la distinzione tra impulso - un evento intenso
e puntuale - e stress - una forza appliccata al sistema che dura nel tempo.
Problemi quando ci sono delle socket.
Dopo una rapida spiegazione del three way handshake si arriva al punto : problemi di grande latenza
nella lettura/ scrittura di dati. Il messaggio è di impostare sempre un timeout differente da quello
di default impostato dal sistema operativo che di solito è dell'ordine di minuti (per quanto riguarda la
scrittura, per la lettura può essere indefinito). Attenzione alla Socket.setSoTimeout() ; prima di usarla
studiare bene cosa fa.
Segue un esempio di un sistema che crollava sempre alla stessa ora, la cui causa si è scoperto essere il firewall.
Ovvero se non c'è trasmissione di dati per molto tempo in una connessione di tipo TCP/IP il firewall
considera gli end point morti, e per lui la connessione non esiste più. Chi legge dalla socket invece
considera la connessione ancora attiva. La soluzione è stata nell'abilitare una funzione di Oracle
chiamata 'dead connection detection' che esegue ping sui client per sapere se la connessione col db
è attiva oppure no. Tale trasmissione di pacchetti ping permette al firewall di considerare la connessione
TCP/IP attiva.
Reazioni a catena.
Si parla di scalabilità orizzontale e verticale. Quella orizzontale indica l'aumento di capacità attraverso
l'aggiunta di server (es: google e amazon), ovvero il concetto di ridondanza. Il difetto è nel sovraccarico
che ogni server attivo deve gestire a fronte di ogni spegimento eccezionale di uno o più server.
Il difetto nel codice che ha generato l'eccezione è presente in ogni singolo application server.
Le reazioni a catena accadono il più delle volte quando ci sono dei thread bloccati; l'applicazione smette
di rispondere e le richieste in ingresso vengono ridestribuite sui server aumentando la probabilità
di fallimento. Un altra causa sono gli outofmemory.
Utenti
:) Qui inizia il paragrafo con la frase "Users are a terrible thing" ; un consiglio è quello di
evitare situazioni di outofmemory, spesso non catturate nei log (es: log4j), mettendo meno informazioni
possibile in sessioni. Ad esempio il risultato di una query al fine della paginazione. Meglio rieseguire
la ricerca ogni volta. In sessione dovrebbero essere salvati dati riutilizzabili.
Mi ha fatto pensare in quali particolari casi può essere utile l'uso di un SoftReference ad un oggetto risorsa.
L'idea è di mettere in sessione un SoftReference all'oggetto in questione al posto del riferimento all'oggetto
diretto. Questo con il vantaggio di rendere disponibile al garbage collector in caso di bisogno l'area
di memoria usata dalla risorsa. Ogni utente in tal modo usa sul server all'incirca la stessa quantità
di memoria. Se però il garbage collector disalloca l'area di memoria referenziata bisogna gestire il caso
in cui l'oggetto viene richiesto da qualche operazione.
In un sistema di ecommerce una parte da testare con riguardo è quella relativa al 'checkout', all'acquisto
di beni. E' un consiglio banale, la parte interessante è legata al fatto che spesso proprio quell'area
è quella che esercita l'integrazione di un gran numero di sistemi (carte di credito, inventario..)
Quindi astraendo la parte più fragile del sistema è quella dove devono collaborare più sottosistemi.
Non conoscevo la definizione di 'conversion rate': la percentuale di visitatori di un sito che acquistano
qualcosa. Se tale conversion rate è di solito del 2 % è opportuno eseguire test di carico di 3-4 volte tanto.
Infine ci sono gli utenti pericolosi, e la mitica DDOS (distributed denial of service).
Nessun commento:
Posta un commento