Facoltà di Ingegneria

Transcript

Facoltà di Ingegneria
Facoltà di Ingegneria
Corso di Studi in Ingegneria Informatica
tesi di laurea
Realizzazione di un framework per la valutazione
dei meccanismi di logging di sistemi software
Anno Accademico 2010-2011
relatore
Ch.mo prof. Domenico Cotroneo
correlatore
Ing. Antonio Pecchia
candidato
Carlo Maietta
matr. 041 - 003740
Alla mia famiglia
Indice
Introduzione
5
Capitolo 1. Utilizzo dei log per la valutazione della dependability
8
1.1
Dependability
8
1.1.1
1.1.2
Dependability attributes
Dependability threats
9
10
1.1.2
Dependability means
13
1.2
Field Failure Data Analysis
1.2.1
Data logging and collection
1.2.2
1.2.3
1.3
Data filtering and manipulation
Data analysis
Contributo della tesi
Capitolo 2. Rule Based Log
14
16
20
22
23
25
2.1
Importanza del Logging Rule-Based
25
2.2
Modello di sistema
28
2.3
Regole di logging
29
2.4
Un’infrastruttura di logging rule-based: Logbus-ng
34
2.5
API di logging per la FFDA in ambienti distribuiti
39
Capitolo 3. Progettazione e sviluppo del framework di valutazione
44
3.1
Struttura
46
3.2
Software Fault Injection
48
3.2.1
Fault Injection Operators
51
3.2.2
Tool per la Software Fault Injection
52
3.3
Monitor FFDA
3.3.1
Sincronizzazione del Monitor FFDA
54
57
III
3.4
Testbed Manager
62
3.4.1
Meccanismi di comunicazione
63
3.4.2
Funzionamento
65
Capitolo 4. Un caso di studio: Apache Web Server
73
4.1
Instrumentazione del codice
74
4.2
Fault Injection
77
4.3
Workload
78
4.4
Ambiente di test
80
4.5
Esecuzione della campagna
81
4.5
Risultati
4.5.1
Benchmark Apache / Logbus-ng
4.5.2
Correlazione col workload
87
88
92
Conclusioni e sviluppi futuri
95
Appendice A. Configurazione consigliata per il framework
97
Appendice B. Configurazione della comunicazione tramite Remote Shell
99
Appendice C. Testbed Manager della campagna di test
101
Bibliografia
106
IV
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Introduzione
Al giorno d‟oggi, l‟impiego di sistemi informatici nella vita quotidiana è cresciuto ed ha
raggiunto un‟importanza tale da risultare fondamentale nella quasi totalità delle attività
umane, agevolando o addirittura rimpiazzando l‟intervento dell‟uomo, al fine di
migliorarne l‟efficienza e l‟affidabilità. In particolare, di notevole importanza è il loro
impiego in scenari fortemente critici, ossia quei sistemi direttamente responsabili della
sicurezza di beni e persone, il cui fallimento potrebbe portare a conseguenze disastrose;
esempi classici possono essere il controllo del traffico aereo e ferroviario, dei veicoli senza
conducente, degli impianti nucleari, di apparecchiature mediche o sistemi bancari.
Risulta pertanto prioritario massimizzare l‟affidabilità (dependability) di tali sistemi, in
modo che ci si possa affidare con un elevato grado di fiducia; si rende quindi necessario lo
studio di tecniche volte al monitoraggio di un sistema al fine di tracciare il suo
comportamento, in modo da poterne misurare il grado di affidabilità, verificando ad
esempio quando e quante volte esso fallisce durante una sua esecuzione, quanto sono gravi
i suoi fallimenti e quanto tempo è necessario al ripristino del corretto funzionamento dello
stesso.
Le tecniche riprese nel presente lavoro di tesi sono state sviluppate secondo i principi
della Field Failure Data Analysis, ossia la raccolta, misurazione e analisi dei dati
direttamente sul campo, in real workload condition, ossia in condizioni di reale
5
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
funzionamento, e sono focalizzate soprattutto sui sistemi software che, a differenza di
quelli hardware che hanno raggiunto ottimi livelli di affidabilità, hanno visto negli ultimi
decenni accrescere notevolmente la loro complessità e di pari passo le probabilità di
fallimenti.
La raccolta dei dati avviene tramite la tecnica dell‟event logging, ossia la registrazione
cronologica su file di informazioni riguardanti le operazioni che man mano vengono
eseguite dal sistema: gli eventi di log solitamente sono generati dal software mediante
degli appositi componenti dell‟applicazione o dell‟ambiente in esecuzione sulla macchina
ove risiede il sistema da osservare, e rappresentano una valida risorsa di informazioni utili
a condurre un‟efficace caratterizzazione dei fallimenti che si sono verificati durante
l‟attività del sistema.
Tuttavia gli studi basati sugli event logs risalgono a tre decenni fa, un arco di tempo nel
quale i sistemi informatici si sono profondamente evoluti, rendendo le classiche tecniche
di logging sempre più inadeguate. Un loro limite importante risiede nel fatto che la
rilevazione di un fallimento dipende fortemente dal fatto che il modulo o l‟applicazione
tenga traccia o meno del particolare evento che ha scatenato il fallimento stesso. In altri
termini, non tutte le possibili condizioni di errore vengono riportate nei log e questo può
senza dubbio rendere molto difficile stabilire tutte le cause principali dei vari eventi di
fallimento osservati durante l‟esecuzione di un sistema software. Tali tecniche, inoltre,
possono risultare inadeguate per alcune tipologie di analisi quali quelle condotte in tempo
reale, come ad esempio possono essere le analisi di sistemi di sicurezza o di controllo di
apparati (centraline, macchinari, etc.).
Per tali motivi sono recentemente state presentate delle nuove strategie, basate su nuove
tipologie di eventi di log, che definiscono un nuovo approccio, definito “rule-based”,
verso un logging più completo ed efficiente, e per le quali è sviluppata un‟infrastruttura
software, il “Logbus-ng”, in grado di raccogliere e distribuire i messaggi di log su
architetture distribuite, in accordo con le nuove regole definite.
Permane però il problema della valutazione di tali meccanismi di logging, la cui efficacia
6
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
a fronte di fallimenti del software è pressoché sconosciuta. In tale ambito si colloca il
presente lavoro di tesi: integrando il Logbus-ng in un più completo ambiente di testing, in
un framework che permetta l‟esecuzione di lunghe campagne di test volte ad una più
ampia, e soprattutto più efficace, log and data collection, secondo le più moderne regole di
logging, si configura come valido strumento per l'assessment dei meccanismi di logging di
sistemi software, in una fase anche antecedente a quella operazionale, in modo da
permetterne un miglioramento ancor prima che esso entri nella piena fase operativa.
Nello specifico, nei capitoli a seguire sarà definito in modo più approfondito il concetto
di dependability e l‟importanza del logging ai fini della Field Failure Data Analysis,
evidenziandone le problematiche che hanno condotto ad un approccio rule-based. Saranno
quindi presentati nel dettaglio il Logbus-ng e le regole sulle quali si basa. Dopodichè
verranno descritti la struttura e il funzionamento del framework, con particolare
riferimento ai tool appositamente realizzati per integrare il Logbus-ng nell‟ambiente di
testing ed automatizzare le campagne di sperimentazione. Infine si porterà l‟attenzione
sulla prima campagna di sperimentazione eseguita, utilizzando tali strumenti, su un caso di
studio reale: Apache web server, cercando di dimostrare non solo la loro effettiva
efficacia, ma anche e soprattutto i reali benefici che si ottengono dall‟utilizzo di tali
meccanismi di logging rispetto a quelli tradizionali.
7
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Capitolo 1
Utilizzo dei log per la valutazione della dependability
1.1 Dependability
La prima definizione di dependability dei sistemi informatici appartiene a Jean-Claude
Laprie [1] che nel 1982 la definì come “...the ability of a system to accomplish the tasks
(or,equivalently, to provide the service) which are expected to it”, ossia la capacità di un
sistema di svolgere il proprio compito (o erogare il servizio) desiderato.
Col tempo tale definizione è stata aggiornata dallo stesso Laprie a “...the ability to
deliver service that can justifiably be trusted”, abilità del sistema di erogare nel tempo un
servizio al quale ci si possa affidare con un giustificato grado di fiducia, fino ad un più
generico “...ability to avoid service failures that are more frequent and more severe than
acceptable”, ossia capacità di evitare che fallimenti siano più frequenti e più gravi di
quanto possa essere tollerato.
La dependability di un sistema rappresenta quindi la capacità degli stessi di mostrarsi
"affidabili" nei confronti degli utilizzatori, consentendo loro potersi "fidare", usufruendo
dei suoi servizi senza particolari preoccupazioni.
Una caratteristica di importanza cruciale in tutti quei sistemi operanti in scenari
fortemente critici quali il controllo del traffico aereo e ferroviario, dei veicoli senza
conducente, degli impianti nucleari, di apparecchiature mediche, di banche di dati
8
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
sensibili, in cui il concetto di rischio (hazard) assume una notevole importanza, dato che
un loro fallimento può condurre a conseguenze catastrofiche per l‟economia, l‟ambiente,
la salute umana.
Mentre negli ultimi decenni l‟affidabilità dei sistemi hardware è andata via via
aumentando, di pari passo è cresciuta la complessità di quelli software, così come le
possibilità che essi possano fallire e, pertanto, garantire e certificare la dependability del
software è divenuto, sia in fase progettuale che in fase esecutiva, un obiettivo primario.
1.1.1 Dependability attributes
Quello di dependability rappresenta un concetto generico, indicante sommariamente il
livello di affidabilità di un sistema, e pertanto in letteratura si tende a scomporlo in
attributi più specifici, in grado di fornire misure più specifiche della qualità del servizio
erogato:
-
Availability: l'attitudine ad essere in grado di svolgere correttamente il servizio
richiesto:
A(t) = P( !Failure in t )
Vale 0 se al tempo t il sistema è in outage, ovvero è fallito, 1 altrimenti. Il valore
medio E[A(t)] è pari alla probabilità che il sistema fornisca un servizio corretto al
tempo t. Si definisce invece con A(0; t) la frazione di tempo in cui il sistema è in
grado di fornire un servizio corretto durante l'intervallo [0; t].
-
Reliability: l‟attitudine a garantire con continuità il corretto funzionamento nel
tempo. Rappresenta la probabilità che il sistema non fallisca mai nell'intervallo di
tempo [0,t] fissato:
R(t) = P( !Failure in (0,t) )
9
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
-
Safety: la capacità di evitare, in caso di fallimento, conseguenze catastrofiche per gli
utenti o l‟ambiente in cui sia, ossia la probabilità che il sistema non subisca fallimenti
catastrofici nell'intervallo [0; t].
S(t) = P( !CatastrophicFailure in (0,t))
-
Maintainability: la semplicità con cui il sistema può essere sottoposto a modifiche
e/o riparazioni.
-
Security: capacità di evitare manipolazioni improprie ed accessi non autorizzati e di
prevenire la diffusione non autorizzata di informazioni.
-
Performability: dalla combinazione degli attributi di performance e reliability, dà
indicazioni sulle prestazioni del sistema in presenza di errori.
1.1.2 Dependability threats
Le minacce (threats) alla dependability di un sistema comprendono tutti quei fenomeni
che ostacolano l'erogazione di un servizio corretto, ossia corrispondente alle specifiche
funzionali.
Ciò che interrompe un corretto funzionamento di un sistema, o meglio la corretta
erogazione di un servizio da parte dello stesso, si definisce guasto o fault: uno stato
improprio dell‟hardware e/o del software, derivante dal guasto di un componente, da
fenomeni di interferenza o da errori di progettazione o errati interventi di manutenzione.
Il guasto si definisce dormiente (dormant), finchè non produce uno o più errori; in tal
caso si definisce attivo (active). L‟errore (error) è la parte dello stato del sistema può
indurlo al fallimento (failure), l‟evento in corrispondenza del quale si passa da servizio
corretto a servizio non corretto. Un errore si dice rilevato se la sua presenza è rilevata dal
sistema (per esempio tramite un messaggio di errore), altrimenti si dice latente. Il periodo
10
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
susseguente un failure, ossia l‟arco di tempo in cui il sistema fornisce un servizio non
corretto si dice di outage. Il passaggio inverso al fallimento, da un servizio non corretto a
un servizio corretto è detto ripristino o service restoration. In particolare un error genera
un failure quando si propaga fino a raggiungere l‟interfaccia del sistema, ossia il confine
dello stesso percepibile da un utente.
I guasti possono essere classificati in base a svariati aspetti :
-
Natura : che indica se un guasto è accidentale (conseguenti a comportamenti
involontariamente non corretti) o intenzionale (dolosi)
-
Persistenza : che indica se un guasto può rappresentare una causa permanente di
generazione di errori (permanent faults) o generare un solo errore e scomparire
(transient fault).
-
Origine : indicante la causa che ha causato il guasto, classificabile in base a:
-
Causa fenomenologica : i guasti possono essere causati da comportamenti
non corretti delle persone (humanmade fault), oppure no (natural faults);
-
Confini del sistema : se i guasti sono localizzati dentro al sistema si parla di
internal faults, altrimenti di external faults;
-
Fase di creazione : se la progettazione o la realizzazione del sistema non è
corretta, per esempio quando non ci si accorge della presenza di bug software, si
lasciano nel sistema, fin dall'inizio della sua vita operativa, dei guasti che sono
definiti developmental faults. Invece i guasti che occorrono durante la vita operativa
del sistema sono definiti operational faults;
11
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Come detto in precedenza, il propagarsi di un guasto fino all‟interfaccia del sistema, ne
provoca un fallimento (failure). I modi in cui un sistema può fallire sono definiti failure
modes e possono essere categorizzati sulla base di quattro aspetti:
-
Dominio: se il valore del servizio erogato dal sistema non si conforma alla specifica
si ha appunto un value failure, se invece è il tempo in cui tale servizio è fornito a non
soddisfare la specifica si è in presenza di un timing failure.
-
Consistenza: nel caso in cui gli utenti di un servizio siano due o più, allora il
fallimento del sistema può essere definito consistente se il servizio errato che viene
fornito è analogo per tutti gli utenti o inconsistente altrimenti.
-
Controllabilità: a volte i sistemi sono progettati per fallire seguendo modalità precise.
Un esempio tipico è dato dai sistemi Safety-critical fail-stop che, in caso di
fallimento, devono fermarsi senza fornire risultati errati all'esterno. I fallimenti che
soddisfano vincoli di questo tipo sono detti controlled failures, gli altri uncontrolled
failures.
-
Conseguenze: i fallimenti possono essere suddivisi sulla base della gravità delle loro
conseguenze. Fallire nell'inviare un fotogramma durante una videoconfenza o nel
controllare l'impianto di sicurezza di una centrale nucleare comporta rischi
incomparabilmente diversi. Per questo motivo i fallimenti possono essere classificati
in vari modi, da minori a catastrofici. Nell'ambito dei sistemi Safety-critical la
12
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
principale suddivisione che viene fatta è tra fallimenti benigni, che hanno
conseguenze accettabili, e fallimenti catastrofici.
1.1.2 Dependability means
Le tecniche con le quali si tende ad incrementare il livello di dependability di un sistema
vengono definite mezzi (means) e sono principalmente quattro:
-
fault avoidance: tecniche orientate a minimizzare la probabilità di occorrenza dei
fallimenti. Tali tecniche, implicano l‟utilizzo di componenti altamente affidabili che,
pertanto, comportano un incremento dei costi;
-
fault tolerance: orientate alla minimizzazione delle conseguenze dei guasti e che
tendono ad evitare che essi possano degenerare in un failure. Tipicamente, esse si
articolano in due fasi (error detection ed error
treatment con annesso
system
recovery) ed impiegano approcci basati sulla replicazione spaziale (usa componenti
hw e/o sw replicati capaci di sostituire il componente guasto) o temporale (si basa
sulla ripetizione di operazioni o sequenze di operazioni).
-
fault removal: tecniche orientate alla individuazione degli errori e alla rimozione dei
guasti durante lo sviluppo o in fase operativa;
-
fault forecasting: si pone, come obiettivo, la stima del numero corrente,
dell‟incidenza e delle conseguenze dei fault. Può essere deterministico (studio degli
effetti dei guasti sul sistema) o
probabilitstico
(stima dei parametri di
dependability).
13
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
1.2 Field Failure Data Analysis
Incrementare il livello di dependability di un sistema critical equivale a massimizzare
l‟efficacia delle tecniche di dependability enhancement descritte finora. Ciò presuppone
un‟adeguata conoscenza del comportamento del sistema: la caratterizzazione statistica dei
failure modes, accanto alla formulazione di modelli realistici, incrementa la predicibilità
del sistema stesso facilitando l‟applicazione di mirate azioni preventive e/o correttive.
La failure data analysis, attraverso la raccolta e l‟esame di dati relativi ai fallimenti, si
configura quale strumento per la valutazione della dependability di un sistema, fornendo
informazioni utili sia alla costruzione di un suo modello di riferimento sia alla
progettazione di nuovi sistemi. Il suo utilizzo avviene in tutte le fasi del ciclo di vita di un
sistema:
Durante la fase di progettazione (Design Phase), è possibile ottenere stime
dell‟affidabilità attraverso modelli e simulazioni (comprendenti anche simulazioni di fault
injection), al fine di studiare le reazioni del sistema, individuando eventuali dependability
bottlenecks e stimando la coverage dei meccanismi di fault tolerance. I feedback ottenuti
risultano particolarmente utili ai system designers in un‟ottica di miglioramento del
progetto e/o di riprogettazione cost-effective.
Nella fase successiva, quella prototipale (Prototype phase), il sistema viene sollecitato
con profili di carico ad hoc (controlled workloads) per poter studiare le sue reazioni a
faults reali (physical fault injection), le sue capacità di recupero in seguito a situazioni di
errore (recovery capabilities) e l‟efficacia delle tecniche di detection (detection coverage).
Uno studio di questo tipo fornisce informazioni circa il failure process del sistema (cioè la
sequenza di stati che esso attraversa dal momento in cui si verifica l‟errore fino
all‟eventuale recovery) ma non consente di valutare misure di dependability quali il
tempio medio tra due failure successivi (MTTF), il tempo medio di ripristino (MTTR).
Nella fase definitiva, quella operazionale (Operational phase), il sistema è osservato ed
esaminato in real workload condition, ossia durante la sua regolare fase di esercizio,
durante la quale esso è sottoposto ad un carico di lavoro quanto più realistico possibile:
14
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
non si è interessati infatti ad introdurre in maniera forzata un comportamento anomalo del
sistema, ma solo monitorarlo in condizioni di reale funzionamento, tenendo traccia di tutti
gli errori e fallimenti osservati durante tale arco di tempo.
L‟utilizzo di tecniche di failure data analysis in questa particolare fase del ciclo di vita di
un sistema è conosciuta in letteratura come Field Failure Data Analysis (FFDA), essendo
appunto un‟analisi effettuata direttamente sul campo (field). Del resto “there is no better
way to understand dependabilty characteristics of computer systems
than by direct
measurements and analysis.” [2], ossia non esiste modo migliore di valutare le
caratteristiche di affidabilità di un sistema se non quello basato sulla misurazione diretta
e sull‟analisi sul campo dei dati.
La FFDA è infatti una delle tecniche maggiormente adottate per valutare il
comportamento di sistemi, in particolare software, durante la loro fase operativa.
L‟obiettivo è quello di ottenere una caratterizzazione quanto più dettagliata possibile della
loro affidabilità e, nel dettaglio, si è interessati a:
- Individuare le modalità di fallimento, identificando le classi di errori/fallimenti che si
manifestano durante l‟esecuzione del software, valutandone gravità e correlazione.
- Individuare le principali cause di malfunzionamenti.
- Analizzare delle distribuzioni statistiche dei fallimenti, dei tempi di guasto e ripristino.
- Valutare la correlazione tra i fallimenti e i workload durante i quali vengono generati.
- Individuare ed isolare eventuali dependability bottlenecks, i cosiddetti “colli di
bottiglia” per l‟affidabilità dell‟intero sistema.
- Produrre un modello di fallimento del sistema in esame.
- Proporre una strategia di tolleranza ai guasti per i futuri sistemi.
- Ottenere risultati che abbiano validità generale, che sono cruciali per guidare la ricerca
15
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
e il processo di sviluppo del software.
La metodologia FFDA consta di tre fasi consecutive ben definite, mostrate in figura:
1.2.1 Data logging and collection
Durante questa fase si raccolgono dal sistema informazioni relative ai suoi failures. In
particolare, consiste innanzitutto in uno studio preliminare del sistema in esame e del suo
ambiente, al fine di decidere quali dati collezionare e come catalogarli, e definire le
tecniche più appropriate per farlo.
Tra le più comuni vi sono sicuramente i failure reports, ossia rapporti sui fallimenti
generati da operatori umani, quali utenti o staff di manutenzione, che riportano
informazioni riguardanti il failure quali la data e l‟ora in cui è avvenuto , la descrizione del
comportamento di failing osservato, il componente hardware/software responsabile e, se
possibile, la radice della causa che lo ha scatenato, le eventuali azioni intraprese per
ripristinare il corretto funzionamento del sistema. Il problema principale di questa tecnica
è che ovviamente i rapporti sono a discrezione di chi li scrive, dunque è probabile che
alcuni fallimenti passino inosservati, oppure che vengano descritti in modo non
sufficientemente esaustivo, o addirittura in maniera discordante tra un operatore e un altro.
L‟eccessiva „discrezionalità‟ insita nei failure reports, rafforza ulteriormente l‟esigenza e
l‟importanza di un‟altra tecnica di data collection, gli event logs: essi sono machinegenerated, ossia sono generati automaticamente dal sistema tramite appositi processi che
girano sulla macchina, riportando informazioni su determinati eventi del sistema, quali il
16
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
time-stamp rappresentante l‟istante in cui ognuno di essi avviene, una sua descrizione,
l‟applicazione o il modulo che lo ha segnalato. Anche in questo caso il limite è sancito dal
livello di accuratezza con cui le applicazioni o i moduli segnalano gli eventi, aggiunto alla
difficoltà con la quale risulta poi difficile risalire alle cause principali di ognuno di essi.
Se nessuna delle due precedenti tecniche è adeguata al sistema o al caso di studio in
esame si può procedere alla creazione di un sistema di monitoraggio mirato
all‟acquisizione dei dati di interesse. Solitamente la raccolta dei dati avviene durante le
condizioni di normale carico del sistema, ma è possibile sollecitare maggiormente il
sistema secondo le esigenze specifiche dell‟analisi. In particolare, come vedremo nei
capitoli a seguire, per i sistemi interattivi può essere utile fornire al sistema carichi di
lavoro che simulano quelli generati da un operatore umano così da ottenere un
comportamento analogo al normale utilizzo.
I file di log sono in genere il primo posto in cui si tende a cercare informazioni quando ci
si rende conto di un‟anomalia o di un fallimento. Ecco perché solitamente consistono in
file di testo decifrabili tramite un qualisiasi editor, di facile lettura e comprensione da parte
degli amministratori di sistema, degli analisti o degli sviluppatori. La scelta del formato
delle informazioni è in genere un problema molto sentito in ogni ambito, ma in questo lo è
ancora di più in quanto, di fatto, non esiste nessuno standard ufficiale, e in circolazione, è
possibile trovare una molteplicità di formati di log, tutti molto eterogenei tra loro.
Probabilmente questa diversità è dovuta al fatto che la gestione dei log è sempre stata fatta
internamente ai team di sviluppo, senza doversi mai preoccupare di accordarsi su un
particolare standard o comunque senza mai seguire una particolare convenzione, lasciando
fino ad oggi il processo di logging estremamente legato alla soggettività del singolo
sviluppatore. Capita spesso, infatti, in particolare nell‟ambito di sistemi software
complessi, che i formati di log differiscano sensibilmente anche tra varie sezioni dello
stesso software. Il bisogno di uno standard è pertanto molto sentito, allo scopo di avere
innanzitutto un unico formato di rappresentazione dei dati (ASCII, Unicode, etc.), oltre
che una sintassi ben definita in grado di esplicitare semplicemente il tipo ed il numero di
17
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
informazioni ad integrazione del messaggio di log stesso, tra cui il timestamp e il
componente sorgente.
Lo standard Syslog
In circolazione sono disponibili diversi tipi di formati e piattaforme più o meno
complete, orientati alla raccolta di messaggi di logging, quali Apache Log4xx, SecureLog
e Syslog [3][4].
Quest‟ultimo, in particolare, è particolarmente diffuso in unix e conseguentemente sotto
linux (mentre non è altrettanto diffuso in ambiente windows). Nato nel 1980 come
componente di Sendmail, agente di trasferimento per la posta elettronica in ambiente unix,
si è diffuso presto e velocemente per la sua semplicità, portando però negli anni alla
nascita di varie implementazioni indipendenti, spesso incompatibili tra loro. Un primo
passo verso la sua standardadizzazione è avvenuto nel 2001 ad opera dell‟IETF che, col
documento 3164 [3], eseguì un‟opera di armonizzazione delle sue regole, cercando di
porre un freno al caos dei formati, definendone uno di fatto derivato da quelli in uso, il
Syslog BSD. Con lo Standard 5424 [4] si è infine formalizzato in modo definivo il Syslog
come protocollo standard, rendendo così obsoleto il formato 3164, che tuttavia è ancora
largamente utilizzato in piattaforme legacy come Linux e MacOS che non sono ancora
pienamente compatibili con il 5424.
Un messaggio Syslog [4] è contraddistinto da una severity, ossia un indice numerico da 0
a 7 rappresentante il suo grado di importanza durante le analisi, a partire da un livello di
debug), salendo verso livelli a gravità superiore, quali avvisi (warning), errori (error),
fino alle condizioni di emergenza (fatal).
Altra informazione presente in un messaggio Syslog è la facility, codifica numerica di un
elenco ben noto, che al valore più basso ha il kernel del sistema operativo, fino a salire ai
livelli dei programmi utente, per un totale di 24 livelli.
La combinazione di severity e facility fornisce il livello di priority, calcolata
moltiplicando per 8 (i livelli di severità, appunto) la facility e ad essa sommando la
18
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
severità del messaggio. Questo comporta che i messaggi di una facility minore hanno
sempre maggiore priorità di quelli di una facility maggiore, come del resto è giusto che
sia, essendo sicuramente un messaggio informativo del kernel prioritario rispetto ad una
qualsiasi anomalia rilevata su un‟applicazione software di alto livello.
Il messaggio Syslog contiene poi una marcatura temporale, indispensabile a disporre i
messaggi di log sulla linea temporale ed effettuare la coalescenza temporale, ma soggetta
ai ben noti problemi di sincronizzazione distribuita o ad errori quale l‟impostazione ad una
data molto antica per via della mancata impostazione del clock di sistema prima dell‟avvio
dell‟infrastruttura di logging, oltre che una sintassi del timestamp rigidamente definita e
riferibile sempre all‟orario UTC, contenendo quindi un offset di fuso orario.
Altre informazioni riportate sono il nome host della macchina che ha originariamente
generato il messaggio, il nome dell‟applicazione ed il suo pid, l‟id del messaggio ed il
messaggio testuale. Tutti questi campi sono opzionali ma indispensabili per una corretta
analisi, seppure, in generale, non sufficienti a caratterizzare in maniera del tutto completa
il comportamento nel dettaglio di un sistema in quanto mancanti di tutte le informazioni
ricavabili invece dal runtime.
Diversi sono i protocolli di trasporto utilizzabili in rete per i pacchetti di log, la cui scelta
è un dettaglio tutt‟altro che irrilevante se si sta analizzando un sistema distribuito su più
nodi in cui sono attivi diversi componenti in grado di poter generare eventi di log.
Generalmente viene utilizzato il classico meccanismo non reliable basato su UDP (RFC
5426), attraverso il porto di default 514, in cui ogni pacchetto UDP deve contenere solo il
messaggio syslog, senza comprendere tutte le eventuali informazioni. Essendo il trasporto
UDP poco affidabile, perché non notifica la eventuale perdita di pacchetti durante il
trasferimento, in particolari applicazioni dove ciò non è tollerabile, si ricorre ad
implementazioni TCP. L‟utilizzo di tale protocollo di trasporto garantisce quantomeno che
non vi siano perdite incontrollate di pacchetti a causa di congestioni della rete, ovviamente
a scapito di una maggiore lentezza e quindi di un impatto maggiore sulle prestazioni del
codice sorgente. Oltre alla possibile perdita di informazioni di log, esiste anche la
19
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
possibilità che alcuni pacchetti vengano intercettati e scartati da un attacker al fine di
nascondere le tracce di una o più operazioni non autorizzate. A fronte di tali casi è
possibile utilizzare sia un meccanismo più complesso ma molto affidabile basato su TLS e
quindi su TCP (RFC 3195). Tale standard si basa sull‟autenticazione ed autorizzazione
mediante certificati che offrono un grado di sicurezza sufficientemente elevato, in modo
da rendere ragionevolmente difficile eseguire attacchi del genere. Va comunque detto che
in generale il trasporto mediante TLS fornisce una sicurezza sulla comunicazione e non
sull‟integrità degli oggetti, ovvero il messaggio nella sua interezza può ritenersi protetto,
ma un dispositivo compromesso può comunque sempre generare indiscriminatamente
messaggi non corretti, inoltre un relay o un collector possono modificare, inserire e
cancellare messaggi senza poter essere in nessun modo controllabili. Per ovviare a queste
situazioni è evidente che avere un canale sicuro come TLS non basta, ma si rende
necessaria l‟adozione di tecniche più sofisticate di detection che vanno al di là dello
standard stesso.
1.2.2 Data filtering and manipulation
E‟ la fase nella quale si effettuano scrematura ed elaborazione dei dati raccolti in modo
da ottenere le informazioni utili per l‟analisi. L‟obiettivo è innanzitutto quello di ridurre il
volume di informazioni da memorizzare e per concentrare l‟attenzione verso un set di dati
più significativo, in modo da semplificare notevolmente il processo di analisi, eseguendo
quindi un filtering: ciò viene fatto eliminando dai log tutti gli elementi della black list,
ossia l‟elenco di tutti i termini che sicuramente identificano un evento di scarso interesse
per l‟analisi, o ammettendo nei log solo i termini ritenuti utili e interessanti ai fini
dell‟analisi, ossia quelli presenti nella cosiddetta white list.
E‟ altresì necessario anche eliminare le entry di dati non validi e, mediante apposite
tecniche di coalescenza, unire quelli ridondanti o equivalenti: tale situazione, infatti, si
20
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
presenta spesso quando si fa un largo utilizzo di eventi di log che, per loro natura,
contengono molte informazioni non collegate necessariamente ai fallimenti del sistema,
presentandosi spesso in forma duplicata o comunque ridondante e ravvicinata nel tempo
quando un particolare evento viene scatenato; evidentemente questi dati devono essere
uniti in un'unica segnalazione relativa all‟evento osservato, detta tupla.
La coalescenza può essere:
-
Temporale: si basa su di un‟euristica temporale, ossia sull‟osservazione che due o più
eventi di fallimento, che si presentano a distanze temporali ravvicinate, sono spesso
dovuti ad una stessa causa: è lecito pensare che gli effetti di un singolo fault possano
propagarsi all‟interno del sistema causando la rilevazione di più eventi di fallimento,
o comunque che un fault possa essere persistente o possa ripetersi nel tempo.
-
Spaziale: raggruppa nella medesima tupla gli eventi che si verificano su nodi vicini
dello stesso sistema; ciò permette ad esempio di identificare la propagazione dei
failures sui vari nodi di un sistema distribuito.
-
Basata sui contenuti (content-based): raggruppa in una singola tupla tutti quegli
eventi relativi ad uno specifico contenuto oppure dello stesso tipo; ad esempio, con
questa tecnica è possibile raggruppare tutti gli eventi relativi al riavvio del sistema.
Ovviamente, al fine di raggruppare eventi failures coalescenti in un‟unica tupla, è
necessario definire una window appropriata (una finestra temporale o una distanza, a
seconda se si tratti di coalescenza temporale o spaziale) entro la quale più eventi
consecutivi vengono ritenuti tali: è importante infatti evitare collisioni (eventi relativi a
due differenti guasti raggruppati nella stessa tupla) o troncamenti (eventi relativi allo
stesso guasto raggruppati in
tuple differenti), che potrebbero portare a perdite o
distorsioni dei dati raccolti.
21
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
1.2.3 Data analysis
L‟output della fase precedente, ossia i dati collezionati e appositamente filtrati, viene
utilizzato in quest‟ultimo step: vengono infatti valutati, a fini statistici, svariati fattori,
come:
-
Error and Failure Classification: le entry di log sono classificate secondo diversi
criteri, quali ad esempio la gravità o il componente che li ha causati. Solitamente
questo è il punto di partenza della fase di data analysis, i cui risultati guidano verso
un‟analisi più specifica, a “grana più fine”.
-
Evaluation and Modeling of Dependability Attributes: vengono valutati gli specifici
attributi di dependability, come la availability, la reliability, e quindi sviluppati
modelli per la descrizione dell‟affidabilità del sistema, come macchine a stati, alberi
di fault, catene di Markov e reti di Petri.
-
Diagnosis and Correlation of Failures: viene valutato, con approcci statistici, se e
come i fallimenti sono correlati tra loro o con altri fattori esterni, come ad esempio il
workload sottoposto al sistema.
-
Failure Prediction: eventi critici, rappresentativi di fallimenti, sono spesso preceduti
da sequenze di eventi a criticità minore nei log. Una branca di letteratura sulla log
analysis ritiene che sia possibile, attraverso l'ossrvazione di questi pattern di eventi a
criticità minore, capire quand'è che sta per accadere qualcosa di veramente grave nel
sistema, disponendo così interventi correttivi proattivi, ossia precedenti al
manifestarsi del failure.
-
Security Analysis: rivolta soprattutto alla valutazione dei log riportanti informazioni
legate alla sicurezza, quali la classificazione e la progressione degli attacchi, e allo
sviluppo di modelli e tool di monitoraggio.
22
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
1.3 Contributo della tesi
Seppure gli studi basati sulla FFDA siano molto utili per valutare i sistemi reali, essi
sono abbastanza limitati nell‟individuazione di alcune categorie di malfunzionamenti. Le
tecniche usate, infatti, non sono disponibili per qualsiasi classe di sistema, o risultano
comunque inadeguate per un certo genere di studi. Le particolari condizioni sotto le quali
il sistema è osservato possono inoltre variare notevolmente da un‟ installazione all‟altra,
causando quindi forti dubbi sulla effettiva validità statistica dei risultati ottenuti. In ogni
caso analisi di questo tipo fanno riferimento a dati relativi ai soli fault rintracciati, cioè
quelli che hanno realmente danneggiato il sistema. Risultano quindi quasi sempre poco
utili a migliorare la versione corrente del software: i maggiori benefici vengono infatti
tratti soprattutto dalle release successive a quella analizzata. Infine è importante tenere
presente che la FFDA può, in generale, richiedere tempi molto lunghi di studio del sistema
sotto osservazione, specialmente nel caso in cui il sistema stesso sia particolarmente
robusto o comunque nel caso i fallimenti fossero molto rari. Al fine di poter realizzare una
validazione statistica e diminuire il periodo di osservazione è necessario che il
meccanismo di logging alla base della fase di data and log collection sia molto efficace di
quanto lo sono gli attuali.
Ecco perché, recentemente, state presentate delle nuove regole che propongono un
approccio al logging differente, e sviluppati degli strumenti basati su di esse, allo scopo di
aumentarne l‟efficienza.
Tuttavia la capacità di logging rispetto a gran parte dei failure non è nota, o comunque
difficilmente misurabile, e si rendono quindi necessari degli strumenti in grado fornire un
l'assessment dei meccanismi di logging, magari anche in una fase anche antecedente a
quella operazionale, in modo da permetterne un miglioramento ancor prima che esso entri
nella piena fase operativa, e il presente lavoro di tesi si propone di fornire un supporto
proprio per questo tipo di valutazioni. E‟ stato pertanto realizzato un framework che,
integrando una serie di strumenti basati sul cosiddetto “rule based log”, crea uno specifico
ambiente di testing, entro il quale è possibile effettuare campagne di testing basate su
23
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
“software fault injection”. Come si vedrà, dall‟analisi dei risultati prodotti da tali
campagne, è possibile ricavare una valutazione dei meccanismi di logging del sistema
software testato.
24
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Capitolo 2
Rule based log
2.1 Importanza del Logging Rule-Based
I benefici mostrati dalla FFDA negli ultimi anni sono stati notevoli e rivolti ad un‟ampia
gamma di sistemi, dai sistemi operativi, ai supercomputers, ai dispositivi mobili. Tali studi
hanno contribuito in modo significate alla comprensione di delle cause e delle modalità di
fallimento di gran parte di questi sistemi, permettendo un costante miglioramento alle loro
successive generazioni.
Il livello di attendibilità di uno studio basato sulla FFDA, è tuttavia strettamente legato
alla qualità, la precisione e l‟affidabilità dei log collezionati, che, come già accennato,
sono da sempre la principale risorsa per la data analysis, ma possono facilmente
compromettere le potenzialità delle analisi FFD basate su di essi, a causa dei molteplici
fattori negativi insiti nella log collection e nella struttura stessa dei file di log.
Il primo fattore negativo è sicuramente quello dell‟eterogeneità: ciò è spesso dovuto alla
scelta di lasciare la gestione e la produzione dei log agli sviluppatori, relegando di fatto
tale operazione alle ultime fasi del ciclo di produzione. Ciò comporta che i file di log
prodotti possano variare significativamente sia nel formato sia, soprattutto, nei contenuti, a
seconda di chi ha scritto lo specifico componente o la specifica sezione di codice, di quali
25
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
eventi del sistema si vuole tenere traccia e delle modalità con le quali si intende farlo.
Tale fenomeno tende ovviamente a verificarsi in modo più marcato e frequente, tanto più è
complesso il sistema in questione.
Altro problema è quello dell‟inaccuratezza: i log possono contenere duplicati e
informazioni inutili, o addirittura possono essere incompleti e quindi mancanti di alcuni
eventi di fallimento. Nel primo caso si può ricorrere, in fase di data filtering and
manipulation, a tecniche di coalescenza ma, allo stesso tempo, tools per l‟analisi
automatica dei log potrebbero raggruppare eventi incorrelati o non raggruppare eventi che
lo sono, provocando collisioni o troncamenti. In ogni caso il problema della perdita di
informazioni relative a failure permane, ed è sicuramente il principale limite delle tecniche
di logging classico. Il tutto senza considerare che, di fatto, non esiste nessuno standard o
strategia comune in grado di dettare le linee guida nella raccolta dei log stessi.
C‟è da sottolineare poi che tutte le tecniche volte a rimodellare i log già generati sono
molto pesanti, soprattutto nel caso di sistemi complessi, e richiedono la stesura di
algoritmi ad-hoc per rimuovere i dati non rilevanti, per eliminare le ambiguità e per fare
coalescenza tra i dati ritenuti correlati.
A dimostrazione di quanto detto finora, è molto utile citare uno studio reale fatto sul
Web Server Apache, riportato in [5], dal quale si è avuta la conferma che la mancanza di
molte entry di log e la loro assoluta incorrelazione ed eterogeneità può inficiare la FFDA
in maniera assolutamente grave: si è giunti infatti alla conclusione che solo il 44% dei
fallimenti del server lasciava traccia nei file di log di Apache.
Risulta quindi evidente che, per superare tutte queste problematiche del classico logging,
non può essere sufficiente una semplice conversione di tutte le entry di log verso un
formato comune, come può essere lo standard Syslog, bensì è necessario adottare regole e
linee guida precise per aumentare l‟efficienza dei file di log e minimizzare gli sforzi di
analisi, effettuando, cioè, un approccio al logging rule-based [6]. In altre parole, è
plausibile che un piccolo sforzo durante le fasi di design e sviluppo possa contribuire a
26
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
produrre dei log che possano essere molto più accurati e utili a rendere quanto più precisi è
possibile i risultati una analisi FFD.
Inoltre un‟altra esigenza molto sentita è quella di avere a disposizione un framework
software per la raccolta e la successiva distribuzione ai client di messaggi di logging. Una
piattaforma dedicata al logging necessita di almeno due funzionalità basilari: deve
consentire allo sviluppatore di creare messaggi con invocazioni non complesse e deve
consentire la memorizzazione permanente degli stessi su disco seguendo un formato
prestabilito. Pertanto, un‟altra strada da perseguire è sicuramente quella di avere dei tool
automatici, raccolti in un framework, per la generazione e l‟analisi (post e/o real time)
degli eventi di log, da fornire agli ingegneri del software, sia per le nuove applicazioni sia
per tutti i sistemi cosiddetti legacy, cercando di renderli quanto più compatibili con la
nuova strategia e con il nuovo strumento in loro possesso.
Lo scopo finale di queste proposte deve essere quello di migliorare la qualità e l‟efficacia
delle tecniche di logging, cercando di ottenere dati accurati e omogenei che sono subito
pronti ad essere analizzati senza nessun‟altro processo di elaborazione. Inoltre si dovrebbe
rendere possibile l‟estrazione (anche on-line) di informazioni aggiuntive a partire degli
eventi di log prodotti dai singoli componenti del sistema sotto analisi.
Per poter fare ciò, è necessario disporre di un modello di sistema abbastanza accurato, in
modo che la conoscenza dei principali componenti e le interazioni tra essi possano
facilitare l‟analisi di correlazione; di regole di logging, il cui scopo è di ottenere dati
omogenei, che saranno generati durante l‟esecuzione di uno specifico istante al fine di
scoprire i fallimenti e facilitare l‟analisi dell‟affidabilità; di un‟ infrastruttura di logging,
ossia una piattaforma utilizzata nei sistemi distribuiti per organizzare i dati raccolti e la
successiva analisi.
27
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
2.2 Modello di sistema
Con la definizione “modello di sistema” [7], si intende una descrizione ad alto livello dei
principali componenti di un sistema e delle loro interazioni. Tali componenti sono
classificati in due categorie:
-
Entità: che rappresentano gli elementi attivi del sistema, ossia tutti quelli in grado di
fornire servizi e/o avviare interazioni verso altre entità o risorse.
-
Risorse: gli elementi passivi del sistema, non in grado di avviare interazioni verso
altre entità o risorse, ma solo di riceverne.
La figura d‟esempio rappresenta le definizioni proposte, evidenziando come risorse ed
entità interagiscono all‟interno di un sistema:
Ovviamente tali concetti sono abbastanza generali, specializzati di volta in volta a
seconda del tipo di sistema e delle esigenze di progetto.
Nell‟ambito di un sistema software, le entità potrebbero ad esempio essere dei processi o
dei threads, che sono sempre elementi attivi di un sistema, mentre le risorse potrebbero
essere dei files o un database. Inoltre le entità potrebbero rappresentare dei componenti
28
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
logici come, ad esempio, del codice eseguibile contenuto in una libreria o in un package,
indipendentemente dal processo che lo esegue. Come si può immaginare, le entità
interagiscono con altri componenti del sistema mediante chiamate a funzione o
invocazioni di metodi, al fine di fornire servizi più o meno complessi.
Nel formalizzare delle regole di logging, in realtà, non c‟è particolare interesse alla
modalità di interazione di un sistema reale, bensì alle proprietà dell‟interazione stessa, che
sono quelle più o meno già accennate in precedenza e ricavabili dalla figura, ovvero:
1 - Un‟interazione è sempre iniziata da un‟entità,
2 - Il suo oggetto può essere una risorsa o un‟altra entità
3 - Essa può anche generare elaborazioni successive, in particolare se coinvolge una o
più entità.
2.3 Regole di logging
A partire dal modello di sistema appena presentato, c‟è da capire in che punto, all‟interno
del codice sorgente di un‟entità, bisogna inserire eventi di log per consentire effettive
misure di dependability. Il logging classico tiene conto di solo due categorie di eventi: gli
informational events, riguardanti lo stato dell‟entità in funzione (running), e gli
exceptional events, riportanti gli errori avvenuti a runtime, che non sono certamente
sufficienti realizzare una strategia di logging che possa superare le limitazioni citate in
precedenza. A queste pertanto si è deciso di affiancare altre due categorie di eventi: i lifecycle events, e gli interaction events [8].
Life Cycle Events:
Questa categoria di eventi fornisce informazioni sul ciclo di vita delle entità, che li
generano secondo regole ben precise, fornendo informazioni riguardo al fatto ognuna di
esse abbia correttamente iniziato la sua esecuzione o che l‟abbia terminata senza problemi.
29
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Essi sono:
SUP: Start-Up generato da ogni entità quando diventa attiva.
SDW: Shut-Down, generato da ogni entità quando termina la propria esecuzione.
Le regole di logging riferite a SUP e SDW impongono che:
Ogni evento di SUP sia loggato come prima istruzione di un‟entità al suo avvio.
Ogni evento di SDW sia loggato come ultima istruzione di un‟entità, prima che essa
termini correttamente.
Le sequenze di SUP e SDW sono molto utili per valutare i parametri di dependability del
sistema, anche in tempo reale, come l‟uptime e il downtime di ogni entità, consentendo
inoltre di identificare i riavvii puliti (clean) e sporchi (dirty).
Interaction Events:
Questa categoria di eventi fornisce consente di conoscere lo stato operativo di un‟entità,
rendendo possibile la scoperta dei loro fallimenti ad esse legate, e di discriminare se essi
sono dovuti ad un‟elaborazione locale o ad un‟interazione fallita con un‟altra entità o
risorsa, ai fini della failure correlation analysis. Essi sono:
SST: Service Start, generato quando ogni entità avvia un servizio
SEN: Service End, generato quando ogni entità termina l‟esecuzione di un servizio.
Secondo le seguenti regole:
Ogni evento di SST va loggato prima dell‟istruzione iniziale di ogni servizio.
Ogni evento di SEN va loggato dopo l‟ultima istruzione di ogni servizio.
La presenza di un SST in seguito ad un SEN garantisce che un‟entità, una volta invocata,
serva completamente l‟interazione richiesta, terminando correttamente la propria
esecuzione. Ovviamente ciò non è sufficiente a mostrare se essa ha fallito a causa di un
errore locale o a causa di un‟interazione non andata a buon fine. Per questo motivo è
importante introdurre degli eventi e regole specifici per le interazioni entità-entità ed
entità-risorsa:
EIS (RIS): Entity (Resource) Interaction Start, generato quando un‟entità inizia
30
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
un‟interazione con un‟altra entità (o una risorsa).
EIE (RIE): Entity (Resource) Interaction End, generato al termine di un‟interazione
entità-entità (entità-risorsa).
Tali eventi sono così regolamentati:
Ogni evento EIS (RIS) deve essere loggato prima dell‟invocazione di ogni servizio.
Ogni evento EIS (RIS) deve essere loggato prima dell‟invocazione di ogni servizio.
Non è consentita nessun‟altra istruzione tra gli eventi EIS (RIS) – EIE (RIE).
Tali regole forniscono la prova rispettivamente che l‟interazione legata ad una certa
entità (risorsa) è iniziata dall‟entità chiamante ed che ha avuto fine.
Poiché un‟entità solitamente fornisce più di un singolo servizio, o comunque inizia più di
una sola interazione, vengono spesso prodotti molti SST ed EIS, e diventa impossibile
collegare ognuno di essi al particolare servizio o interazione di cui fanno parte. Per
ovviare a questo problema, gli eventi di inizio e fine legati ad ogni servizio o interazione
all‟interno della stessa entità, devono essere loggati insieme ad una chiave univoca. E‟
evidente che l‟uso massiccio delle regole di logging può compromettere la leggibilità del
codice, tuttavia, sfruttando la loro semplicità, è possibile creare dei supporti ad-hoc per
automatizzare l‟inserimento delle chiamate di log appena prima della fase di compilazione
dei sorgenti. Un approccio del genere renderebbe la scrittura delle regole del tutto
trasparente agli sviluppatori e non richiederebbe una modifica diretta del codice sorgente.
L‟utilizzo congiunto del modello e delle regole proposte, fa percepire il sistema, dal
punto di vista dell‟analista, come un insieme di entità, ognuna in grado di produrre un
flusso di eventi. Questi flussi possono essere utilizzati per estrarre, durante l‟esercizio del
sistema, utilissime informazioni riguardo allo stato corrente dell‟esecuzione di tutte le
entità, così come di scoprire eventuali occorrenze di fallimenti.
E‟ evidente che le regole sopra enunciate impongano che i messaggi di log siano forniti
in coppie inizio-fine, cioè un SST deve essere seguito dal corrispettivo SEN, così come un
EIS deve essere seguito dal suo EIE (analogamente per le risorse). E‟ possibile quindi
31
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
misurare il tempo trascorso tra due eventi collegati (ad esempio l‟inizio e la fine dello
stesso servizio o interazione) durante ogni operazione del sistema conclusasi senza
fallimenti di nessun tipo, in modo da tenere costantemente aggiornata la durata attesa di
ogni coppia di eventi.
Dopo aver impostato un timeout appropriato, entro il quale un segnale di End è atteso
dopo il corrispondente Start, è possibile quindi prevedere un meccanismo che generi
automaticamente degli alert ogni qual volta il timeout scade senza che il corrispondente
messaggio di End sia stato ricevuto.
Con riferimento agli eventi di log definiti in precedenza, è possibile definire tre tipi di
alert differenti:
- EIA: Entity Interaction Alert, generato quando un messaggio di EIS non è seguito dal
suo corrispettivo EIE all‟interno della sua finestra temporale.
- RIA: Resource Interaction Alert , generato quando un messaggio di RIS non è seguito
dal sui corrispettivo RIE all‟interno della sua finestra temporale.
- COA: Computation Alert, generato quando un messaggio di SST non è seguito dal suo
corrispettivo SEN all‟interno della sua finestra temporale e non sono stati già generati un
EIE o un RIA.
Accanto ad essi, è peraltro utile definire un quarto tipo di alert, legato all‟evento detto
Complaint (CMP), da sollevare quando lo sviluppatore ritiene che l‟entità stia
32
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
continuando ad operare eseguendo una sezione di codice in seguito ad un fallimento di
valore.
Un computation alert risulta evidentemente legato ad uno o più problemi locali rispetto
alla entità che lo ha generato, mentre un interaction alert riporta un comportamento errato
dovuto ad una causa esterna all‟entità interessata. Come già detto, il fenomeno della
propagazione degli errori è dovuto alle interazioni tra i componenti di un sistema e, in
genere può portare alla generazione di molteplici alert. La coalescenza, in questi casi,
rende possibile ridurre il numero di informazioni in eccesso unendo più alert distinti per
formarne uno solo, rendendo così l‟analisi più agevole. L‟approccio tradizionale è quello
citato in precedenza, basato sulle tecniche di coalescenza temporale, che affronta
solitamente l‟eccesso di alert con strumenti esclusivamente time-based, ma senza nessuna
vera consapevolezza della reale correlazione tra i messaggi di log raccolti.
L‟uso di precise regole di logging riduce significativamente lo sforzo da profondere in
fase di analisi, e incrementa considerevolmente l‟efficacia della fase di coalescenza. E‟
evidente, infatti, che gli eventi di interazione rendono possibile la discriminazione tra le
diverse tipologie di alert, ognuna delle quali ha il suo specifico significato: COA e RIA
permettono di identificare i fallimenti della sorgente, mentre gli EIA sono utilissimi per
tracciare i fenomeni di propagazione degli errori.
La strategia più semplice per realizzare un approccio Rule-Based di un sistema software
è quella di modificare il codice secondo le seguenti regole:
1) Per ogni entità che fornisce uno o più servizi, si deve circondare l‟intero metodo con
un blocco try-catch-finally (se il linguaggio lo consente , altrimenti una tecnica simile). La
prima istruzione del blocco try deve essere il log di un evento SST. Il blocco catch deve
loggare esclusivamente il messaggio CMP ed effettuare il throws dell‟eccezione catturata,
mentre il blocco finally deve contenere solo il messaggio di SEN.
2) Bisogna circondare ogni chiamata a metodo in cui è stata applicata la regola 1 con le
istruzioni di EIS ed EIE rispettivamente appena prima e appena dopo la chiamata in
33
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
questione.
3) Si deve circondare ogni chiamata a metodo in cui non è stata applicata la regola 1 e di
cui si ipotizza un potenziale fallimento, con le istruzioni di RIS e RIE rispettivamente
appena prima e appena dopo la chiamata in questione.
La ragione per la quale è utile usare il blocco try-catch-finally è quella di minimizzare i
punti in cui effettuare la instrumentazione del codice. L‟evento SST può essere messo in
maniera univoca all‟inizio del metodo, mentre l‟evento di SEN va ovviamente messo
prima di ogni punto di return, ed inoltre si dovrebbero considerare tutte le possibilità di
fallimenti di valore non gestiti all‟interno del metodo in questione. Il blocco finally
garantisce che l‟evento di SEN venga loggato come ultima azione del metodo chiamato, in
modo che il controllo non venga restituito se prima il messaggio non viene inviato. Il
blocco catch, invece, garantisce che se il metodo originale doveva sollevare un‟eccezione,
questa viene comunque propagata, ma solo dopo aver loggato un CMP. E‟ molto
importante che l‟eccezione venga propagata dopo aver loggato il messaggio di CMP in
modo da lasciare inalterato il comportamento originale del metodo in questione.
2.4 Un’infrastruttura di logging rule-based: Logbus-ng
Nei paragrafi precedenti è stato definito un modello di sistema e una strategia di logging
basata su una serie di regole ben precise, in accordo alle quali le entità sono fonte di eventi
di log. Il sistema, nel suo complesso, risulta quindi essere un “produttore” di logs, mentre
gli sviluppatori e gli analisti di eventi di log sono i “consumatori” finali ad essi interessati,
ai fini della data analysis. Ecco perché risulta necessaria un‟infrastruttura in grado di
collegare “produttori” e “consumatori”, che si interfacci, da un lato, col sistema,
raccogliendo le informazioni di log, e le distribuisca, dall‟altro, ai clients interessati,
rappresentati da componenti pluggable, tramite appositi canali di comunicazione. Una
piattaforma del genere agisce nella sostanza come un bus software per il trasporto di
34
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
eventi di log, il che giustifica il nome “LogBus”, assegnatole in [8].
In particolare, l‟infrastruttura software per il logging utilizzata nel presente lavoro di tesi
è il “Logbus-ng” [9], così chiamato perché progettato e sviluppato seguendo i principi del
LogBus definito in [8], a cui è stato aggiunto il suffisso “ng” che sta per “nextgeneration”.
Scritto nel moderno linguaggio C# e sviluppato per girare sulla la relativa piattaforma
Common Language Runtime, di cui le implementazioni commerciali disponibili sono
.NET per Microsoft Windows e Mono per ambienti POSIX, ha un‟architettura suddivisa in
tre segmenti principali: il segmento delle sorgenti di log, quello del core che gestisce flussi
e canali, e infine il segmento dei clients, denominati più specificamente monitor.
Progettato ovviamente nell‟ottica di
soddisfare i requisiti del LogBus [8], è una
piattaforma software che si occupa di acquisire i messaggi di log, per via remota, dalle
applicazioni e/o dai sistemi operativi che li producono, per poi inoltrarli, inalterati, verso
client remoti che effettuano una apposita sottoscrizione ad un canale. Il formato dei
messaggi di log ricevuti deve rispettare lo standard Syslog BSD o Syslog 2009, anche se è
possibile fornire supporto ad altri formati di messaggio, in ingresso o in uscita, mediante
componenti plug „n‟ play.
I protocolli di trasporto supportati sono gli stessi di Syslog, ossia UDP o il più sicuro (ma
meno performante) TLS.
Altri requisiti non funzionali che si è cercato di soddisfare in fase di progettazione sono:
-
Il nodo bus deve poter girare sulle maggiori piattaforme hardware/software.
-
L‟impatto prestazionale deve essere minimo.
-
Il bus deve poter supportare elevati volumi di traffico senza ripercussioni.
-
Il bus deve poter consegnare i messaggi in maniera affidabile, se richiesto dal client
in fase di sottoscrizione, senza impattare sulle prestazioni degli altri client.
-
Il bus dovrebbe poter essere replicato o distribuito su più nodi.
35
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
L‟implementazione C# del core prevede un modello basato su una pipeline a quattro
stadi: stadio di ingresso (inbound channel), stadio di smistamento (hub), stadio dei canali
di uscita (outbound channel), stadio di trasporto in uscita (outbound transport).
La figura sottostante ne spiega chiaramente la struttura, lasciando intuire le modalità e le
opportunità di funzionamento dello stesso Logbus-ng.
Se ad esempio si volessero collezionare i messaggi di log tramite UDP, TLS e dal
servizio Event Log di Windows, ciascun canale, rappresentato da un cerchio Inbound
Channel, presenta le proprie peculiarità implementative, ma tutti forniscono in uscita
messaggi nel formato Syslog (evidentemente quelli di Windows Event Log vanno
opportunamente convertiti). L‟hub, da questa prospettiva, riceve i messaggi e li inoltra a
ciascun canale in uscita, rappresentato da un cerchio Outbound Channel e il cui unico
scopo è decidere se il messaggio dovrà essere o meno inoltrato ai client in base al
corrispondente filtro; per fare questo, ciascun canale dispone di uno o più gestori delle
36
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
interfacce di trasporto in uscita, rappresentate dai cerchi Outbound Transport, che
gestiscono la consegna effettiva al client remoto. Gli Outbound Transports rappresentano
le istanze di ciascun tipo di gestore, e sono considerati essere multicast: un gestore per il
trasporto TLS, ad esempio, viene istanziato da tutti i canali su cui almeno un client è
sottoscritto con quel tipo di trasporto, e ciascun gestore TLS possiederà la lista dei client
remoti a cui inviare i messaggi tramite messaggi unicast come previsto dal protocollo.
Il ruolo dell‟Outbound Channel ci permette di enunciare e sottolineare un‟altra grande
peculiarità del Logbus-ng: il filtraggio a monte dei messaggi, ad opera del core. Come già
accennato nei precedenti capitoli, la fase di data filtering è necessaria per poter escludere
quei messaggi di log che non contengono informazioni utili ai fini della data analysis. Se è
vero che nelle analisi manuali può essere utile tenere ugualmente traccia dei messaggi di
debug o simili al fine di ottenere maggiori informazioni sul contesto, è altrettanto vero che
in caso di analisi automatiche non è possibile estrarre contenuti informativi utili da
messaggi non conosciuti dall‟applicazione che li elabora. Senza contare il fatto che una
grossa mole di messaggi non filtrati comporta un notevole overhead sia in termini di
traffico sulla rete sia di elaborazione dei messaggi stessi.
Ecco perché ad ogni canale in uscita del Logbus-ng è associato un filtro booleano. I
principali filtri adoperati in questa piattaforma sono tutti modellati sul formato del Syslog
2009, e sono i seguenti:
-
True (False): filtro che accetta (rifiuta) qualsiasi messaggio.
-
And (Or): filtro composto che accetta il messaggio solo se tutti i filtri (almeno uno
dei filtri) che lo compongono danno (dà) esito positivo.
-
Not: filtro composto che dà esito opposto rispetto al filtro che lo compone.
-
RegexMatch: il messaggio è accettato solo se rispetta la Regular Expression fornita.
-
SeverityFilter: confronta la Severity del messaggio con un valore fornito applicando
l‟operatore di confronto scelto dall‟utente (es. [>=, Warning] è una valida coppia
37
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
[operatore, valore] e accetta i messaggi con valore di severity minore o uguale di 4).
-
CustomFilter:
tramite
componenti
pluggable,
è
possibile
realizzare
filtri
personalizzati, richiamabili mediante appositi tag identificativi e un insieme di
parametri liberi, definiti tramite contratto di design.
Pertanto, tutti i client che effettuano una sottoscrizione ad un determinato canale di
uscita, ricevono determinati messaggi di log secondo le regole dello specifico filtro
associato al canale stesso. Ecco perché il Logbus-ng consente a qualunque cliente di creare
(ed eliminare) canali di uscita, fornendo un proprio filtro.
L‟accesso degli eventuali client al Logbus-ng avviene tramite un‟apposita interfaccia,
derivante da una specifica IDL/WSDL, in cui sono stati descritti i metodi ritenuti necessari
alla corretto utilizzo delle funzionalità del bus software:
-
ListChannels, per elencare i canali disponibili per la sottoscrizione.
-
GetChannelInformation, per raccogliere informazioni circa un canale esistente.
-
CreateChannel e DeleteChannel, per creare ed eliminare un canale rispettivamente.
-
GetAvailableFilters, per richiedere al server quali filtri personalizzati sono disponibili
in aggiunta a quelli predefiniti di cui abbiamo discusso.
-
GetAvailableTransports, per richiedere al server la lista dei protocolli di trasporto
disponibili tra cui scegliere.
-
SubscribeChannel e UnsubscribeChannel, per le operazioni di sottoscrizione.
Sicuramente il metodo SubscribeChannel richiede come parametri un identificativo per il
canale e l‟identificativo del protocollo di trasporto da usare, inoltre un client deve fornire
al server alcuni parametri di trasporto per sottoscrivere un canale Syslog. Supponendo di
voler utilizzare UDP come trasporto, questi parametri sono ragionevolmente indirizzo IP e
porto destinazione. In questo specifico caso, per le caratteristiche del protocollo, non è
possibile rilevare un fallimento del client, ed inoltre questo, una volta tornato in vita,
potrebbe non essere in grado di recuperare o annullare la sua vecchia iscrizione al canale:
38
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
il metodo RefreshSubscription dell‟interfaccia serve proprio a questo. Ovviamente il
meccanismo di refresh utilizza un certo time-to-live per la sottoscrizione di ciascun
canale, sicché se il client non invoca il metodo entro il TTL, la sottoscrizione decade e il
server cessa l‟invio dei datagrammi.
Infine, i segmenti sorgente e monitor sono definiti da apposite interfacce mediante
contratti di servizio e protocolli di rete basati su TCP/IP, ed implementati da apposite API
per i maggiori linguaggi di programmazione, e la struttura così flessibile del Logbus oltre
ad essere un requisito fortemente voluto in fase di progettazione dell‟architettura generale,
si rivela essere un‟arma molto potente per chi fosse interessato a svilupparne, sia lato
sorgente che lato client (o monitor).
2.5 API di logging per la FFDA in ambienti distribuiti
Si sono finora descritti il modello di sistema, le regole di logging e la piattaforma che
sono alla base del meccanismo di log collection del presente lavoro di tesi. In particolare,
nel descrivere le caratteristiche del Logbus-ng [9],
si è evidenziato come esso sia
strutturato in tre segmenti distinti; due di essi sono definiti da apposite interfacce ed
implementato da opportune API:
-
quello delle sorgenti, demandato alla produzione e instradamento sul bus dei
messaggi di log;
-
quello dei monitor, demandato alla gestione dei clients che effettuano sottoscrizioni
ai canali del bus e alla consegna ad essi dei messaggi di log.
A tal proposito, di notevole interesse ai fini del presente lavoro di tesi, è una API di
logging per la Field Failure Data Analysis in ambienti distribuiti [10], oggetto di
sperimentazione del framework realizzato che sarà descritto in seguito, che comprende un
insieme di tools e librerie realizzati in linguaggio C#, la cui implementazione è avvenuta
39
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
parallelamente a quella dello stesso Logbus-ng con cui si interfacciano. Le funzionalità
racchiuse in essa sono volte a rendere possibile, e anche semplice, l‟applicazione delle
regole di logging al sistema in esame, la creazione e la gestione dei canali di uscita (e
relativi filtri) verso i monitor, la stampa a video e/o su file dei messaggi consegnati (e
prefiltrati) dal logbus.
La API si divide sostanzialmente in due sezioni, quella per produrre i Log e quella per
riceverli ed analizzarli.
La API lato sorgente è implementata come un‟estensione del core principale del
Logbus-ng [9] , e pertanto viene distribuita come dll stand-alone nel Package Extensions.
Un qualsiasi software che voglia loggare sul bus, definito per l‟appunto logger, deve
utilizzare tale libreria, includendola nei suoi riferimenti, e costruire un‟istanza della classe
FFDALogger mediante i meccanismi messi a disposizione dalla API. Essa infatti si basa
sul meccanismo del pattern factory, in modo da rendere assolutamente trasparente al
programmatore la fase di creazione e valorizzazione dell‟oggetto Logger dedicato alla
FFDA. Per l‟utilizzo di tale factory, è necessario utilizzare le interfacce offerte dalla API
nella classe pubblica FieldFailureDataHelper, ma è prevista anche una fase di
inizializzazione che può semplicemente essere fatta mediante un file xml. Per maggiori
dettagli sull‟utilizzo della factory e/o per la configurazione del relativo file xml ai fini
della gestione dei logger, si demanda a [10] e alle appendici della documentazione del
Logbus-ng [11].
Le interfacce fornite lato produttore (source) sono state ovviamente specializzate per
gestire la produzione degli eventi specifici della FFDA, ovvero i messaggi già analizzati
nell‟approccio Rule-Based descritto in precedenza, loggati dai metodi presenti
nell‟interfaccia:
void LogSST(String id);
void LogSST();
void LogSEN(String id);
void LogSEN();
void LogEIS(String id);
void LogEIS();
void LogEIE(String id);
void LogEIE();
40
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
void LogRIS(String id);
void LogRIS();
void LogRIE(String id);
void LogRIE();
void LogCMP(String id);
void LogCMP();
Si noti che per ogni metodo c‟è una corrispondenza con uno degli specifici messaggi
FFDA relativi agli interaction events, e che per ognuno di essi è previsto un overload, in
modo tale che ad ogni metodo possa essere passata la stringa rappresentante il flusso di
esecuzione (id) che, nel caso non fosse specificata, si assume essere uguale al codice hash
del thread che esegue la chiamata di log.
In relazione ai life-cycle events della FFDA, si ricorda fa notare che quando un logger
viene istanziato per la prima volta, dalla factory o anche direttamente dallo sviluppatore,
esso genera un messaggio SUP, mentre, quando va in Garbage, il suo distruttore invia un
evento di SDW.
In fase di configurazione è possibile inoltre specificare un heartbeat automatico, che
consente di monitorare lo stato operativo dell‟entità quando essa non sta inviando
messaggi FFDA al Logbus (e quindi ai
monitor in ascolto) rendendo facile
l‟individuazione degli hang, segnalati da appositi messaggi “PING FAILED”.
La API lato sorgente fornisce anche alcune agevolazioni per l‟analisi dei monitor FFDA,
rendendo disponibili, se possibile, informazioni aggiuntive alla semplice tipologia di
evento osservato. In particolare, in accordo con l‟RFC5424 [4] si osserva che:
-
Il Message ID è uguale ad FFDA.
-
La Facility è Local0 di default.
-
La Severity è Info per tutti i messaggi eccezion fatta per quello di COA che ha
Severity pari ad Alert.
-
La Structured Data contiene un‟entry CallerData con i campi ClassName,
MethodName e Logger valorizzati, se possibile, rispettivamente con il nome della
classe, il nome del metodo chiamante e il nome del Logger che ha generato il
messaggio.
41
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
-
Il campo Text contiene il tipo di messaggio (SST, SEN, etc.) e, se è presente un ID
del flusso di esecuzione, esso verrà riportato alla fine dopo il separatore “-“ (SST413740).
Tutte queste
funzionalità descritte
forniscono un‟enorme versatilità di utilizzo,
rendendo molto agevole, agli sviluppatori, l‟integrazione della libreria con la loro
applicazione, inoltre rendono possibile, come già osservato in precedenza, la realizzazione
di compilatori instrumentanti in grado di inserire nei punti cruciali del codice sorgente gli
eventi di log, sulla base delle regole definite nell‟approccio Rule-Based.
La API lato sorgente prevede, in realtà, anche una (più snella) implementazione in
linguaggio C, per favorirne l‟integrazione su sistemi sviluppati in tale linguaggio, che sarà
descritta meglio nei prossimi capitoli, quando sarà esaminato un caso di studio con il web
server Apache, scritto e compilato, per l‟appunto, in C.
La API lato client (monitor) deve fornire una serie di funzionalità volte a rendere
possibile la detection di eventuali fallimenti avvenuti durante la fase di raccolta della
FFDA. In altre parole deve fornire gli strumenti per applicare le regole di alerting già
proposte nell‟approccio Rule-Based descritto in precedenza. Di conseguenza, quando si
vanno ad analizzare i log, bisogna tenere conto che la coppia di messaggi SST / SEN
relativi alla stessa entità stanno a significare che il servizio invocato è terminato con
successo, mentre altre situazioni possono indicare un fallimento in accordo con la
trattazione teorica delle logging rules fatta in precedenza.
Per poter ordinare i messaggi di log (che non sono ordinati temporalmente in base ai loro
timestamp) lato client, ovvero una volta recapitati dal Logbus al monitor, vengono
utilizzate le relazioni happened-before, in accordo alle regole di logging nei paragrafi
precedenti. Infatti, se le regole di logging sono così implementate, allora per ogni flusso
di esecuzione valgono le seguenti considerazioni:
-
L‟evento SST è precedente ad ogni altro messaggio.
-
L‟evento EIS è precedente all‟evento EIE.
42
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
-
L‟evento RIS è precedente all‟evento RIE.
-
L‟evento EIS è precedente all‟evento SST del metodo chiamato.
-
L‟evento SEN è precedente all‟evento EIE del chiamante.
Ovviamente, la API lato monitor deve necessariamente dare la possibilità agli
sviluppatori di tracciare con precisione i flussi di una specifica entità, ecco perché,
all‟interno del core principale del logbus, è presente uno speciale plugin, l‟Entity Plugin,
il cui scopo è proprio quello di memorizzare tutte le entità attive nel sistema, creando
appositi canali a cui un monitor, mediante la API deve poter iscriversi in modo da poter
visionare tutte le attività svolte dalla entità di interesse.
Anche la creazione del monitor prevede un meccanismo di factory, grazie alle interfacce
definite nella classe ClientHelper, o una fase d‟inizializzazione che può essere fatta
mediante file xml; anche qui, per ulteriori dettagli si rimanda a [10] e alle appendici della
documentazione del logbus [11].
43
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Capitolo 3
Progettazione e sviluppo del framework di valutazione
Nel precedente capitolo sono stati discussi i meccanismi principali di un approccio al
logging rule-based, sottolineandone l‟importanza ai fini di più agevole e più efficiente
Data Analysis. Sono, inoltre, stati descritti alcuni tools utili alla produzione, distribuzione
e raccolta, secondo tali regole, dei messaggi di log nell‟ambito della Field Failure Data
Collection.
Un sistema in grado di produrre log accurati, specifici e di facile comprensione, permette
senz‟altro una più facile e rapida individuazione dei faults in esso presenti, e di
conseguenza è in grado di raggiungere velocemente innanzitutto un alto livello di
maintainabilty, nell‟ottica poi di un complessivo incremento della sua dependability.
Quello dei log è a tutti gli effetti un vero e proprio strumento per l‟assessing, e di
conseguenza l‟improving, dell‟affidabilità di un sistema, e più in generale della sua
qualità, la quale risulta quindi strettamente legata alla qualità dei log stessi. Ciò rende
pertanto necessari degli strumenti che permettano di valutare l‟efficienza dei meccanismi
di logging stessi, nonché delle relative piattaforme che ne permettono il funzionamento.
In merito a tale questione, c‟è da sottolineare un altro aspetto importante riguardo le
classiche tecniche di logging applicate nell‟ambito della FFDA: così come il sistema che
produce i log, anche il meccanismo di log stesso viene valutato ed eventualmente
perfezionato in base alle informazioni raccolte durante la fase operazionale. Tutte le più
44
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
comuni piattaforme di logging, come ad esempio UNIX Syslog o Microsoft‟s event
logger, collocano eventi da loggare su file all‟interno di percorsi di esecuzione che
possono condurre ad uno stato di fallimento (ad esempio, un‟asserzione riguardo la
correttezza di una variabile: un evento di log viene prodotto se tale asserzione viene
violata), o se si è pervenuti ad uno stato di fallimento. Sistemi software che operano su
piattaforme del genere, qualora sollevano, durante la fase operativa, dei fallimenti,
producono quei file che, una volta filtrati, manipolati ed analizzati, permettono agli
sviluppatori di apportarne miglioramenti sia in termini di qualità del servizio sia per
quanto riguarda la produzione degli eventi di log stessi.
L‟approccio adottato in questo lavoro di tesi, invece, guarda alla questione da un‟altra
prospettiva: valutare il meccanismo di logging in una fase antecedente a quella
operazionale, in modo da permetterne un miglioramento prima ancora che il relativo
software entri nella piena fase operativa. L‟idea di fondo è quella di utilizzare sistemi
software resi artificialmente faulty, in modo tale da provocarne facilmente dei fallimenti,
ove “stressati” con un carico di lavoro approssimabile a quello al quale vengono
solitamente sottoposti durante la loro fase operazionale. Rilevando quindi le occorrenze di
tali fallimenti, e verificando quante e quali entry vengono riportate nei file di log in
corrispondenza degli stessi, è possibile produrre una caratterizzazione statistica del
meccanismo di logging in esame, e quindi una valutazione tale da permetterne il
perfezionamento: ad esempio, un semplice matching tra fallimenti occorsi e log non
riportati, può velocemente portare all‟identificazione di aree nel codice sorgente presso le
quali esso può essere migliorato. Più precisamente, quello che si intende eseguire è una
campagna per la raccolta di log consistente in una (lunga) serie di test, ognuno dei quali
coinvolge una versione faulty del software in esame (verosimilmente una versione
contenente un singolo fault).
Tutto ciò ovviamente necessita di uno specifico ambiente di testing, entro il quale
agiscano un sistema faulty da stressare, con un apposito generatore di workload, al fine di
45
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
provocarne fallimenti, degli strumenti in grado di rilevare questi ultimi, dei meccanismi e
una piattaforma di logging che operino secondo le regole enunciate nel precedente
capitolo.
A tal fine, nell‟ambito del presente lavoro di tesi, è stato progettato e realizzato un
framework che permette di ricreare facilmente un ambiente del genere, racchiudendo i
software in grado di svolgere le azioni sopracitate e coordinando le interazioni tra di essi, e
di rendere quanto più automatiche e veloci possibile le esecuzioni di lunghe campagne di
test rivolte all‟assessment di meccanismi di logging.
3.1 Struttura
Entrando più nel dettaglio, esso innanzitutto incorpora dei tool che rappresentano delle
entità “platform indipendent” del framework, perché indipendenti dalla particolare
piattaforma software da valutare:
-
Un tool di fault injection, che sarà descritto in seguito, necessario a creare delle
versioni faulty del sistema software da testare.
-
Il Logbus-ng [9] e le sue API [10], descritti nel capitolo 2, necessari per la raccolta,
il trasporto e la distribuzione ai client (monitor) dei messaggi di log.
-
Un Monitor FFDA, ossia una piccola applicazione, dotata anche di una semplice
interfaccia grafica, basata sulle API già disponibili [10], creata ad hoc per gestire la
ricezione dei messaggi di log, fungere da Alert Detector, e produrre quindi i relativi
file di log “lato monitor”; il tutto in perfetta sincronia con il “lato sorgente”, ossia il
software, e tutte le altre entità attive durante la campagna di test.
Queste tre entità rappresentano il fulcro del framework e, essendo ampiamente
parametrizzate, possono facilmente integrarsi con svariati sistemi software. Ad esse infatti
vengono affiancati i seguenti componenti, che per la loro natura sono ovviamente
“custom”:
46
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
-
La piattaforma software da testare, nella quale vengono iniettati dei guasti per
provocarne dei fallimenti e quindi collezionarne i log.
-
Un generatore di workload in grado di stressare, con un carico di lavoro quanto più
realistico possibile, il software in esame, e pertanto fortemente legato alla natura
dello stesso.
Tali componenti, sia quelli definiti “platform-indipendent” che quelli “custom”, sono
guidati e coordinati dall‟entità principale del framework, ossia il Testbed Manager, un
eseguibile che pilota tutte le operazioni necessarie a svolgere la campagna di test: in
seguito sarà meglio definito il suo funzionamento e come grazie ad esso sia possibile
eseguire, in modo totalmente automatico, campagne con migliaia di esperimenti. Volendo
fare un‟analogia con i classici linguaggi C/C++, si potrebbe dire che il Testbed Manager
rappresenti il main(), mentre gli altri componenti l‟insieme delle classi e/o dei metodi da
esso invocati. Poiché il suo scopo è anche quello di portare insieme i due “mondi” presenti
nel framework, ossia i suoi tool principali e il software (e relativo workload generator) da
testare, anche il Testbed Manager consta di una parte per così dire “fissa”, ed una che va
47
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
resa "custom", per interagire con il software "ignoto", a tempo di design del framework
stesso.
La figura dà un‟idea sull‟architettura del framework, indicando anche la sequenza delle
tre principali operazioni svolte dal Testbed manager durante ogni esperimento, oltre
ovviamente quelle di sincronizzazione con gli altri componenti, e per le quali si entrerà nei
dettagli nei paragrafi successivi.
A proposito, poi, degli ambienti (hardware e software) nei quali far operare le varie entità
del framework, c‟è da dire che, mentre quelli sui quali dovranno essere eseguiti il software
in esame e il workload generator sono ovviamente vincolati alle particolari caratteristiche
degli stessi, per quanto riguarda le entità cosiddette “statiche” (Logbus-ng, Monitor
FFDA, Testbed Manager) i vincoli sono sicuramente meno stringenti, avendo essi un buon
grado di portability. Tuttavia, le loro attuali caratteristiche hanno suggerito, anche per
motivi prestazionali, l‟utilizzo del Logbus-ng e del Testbed Manager in ambiente UNIXLINUX, del Monitor FFDA in ambiente Microsoft Windows. Inoltre, vista la necessità di
simulare un ambiente distribuito quanto più realistico possibile, si è deciso di mantenere
queste 3 entità su 3 macchine distinte.
3.2 Software Fault Injection
Il primo passo da eseguire nell‟ottica di un assessment di un meccanismo di logging in
una fase pre-operativa, è quello di ottenere delle versioni faulty del sistema software sul
quale eseguire i test; ciò viene fatto tramite una campagna di fault injection. Quella della
48
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Software Fault Injection (FI) è una tecnica ben conosciuta nell‟ottica della dependability
evalutation, e consiste in una deliberata alterazione del sistema software, in modo da
provocarne artificialmente l'occorrenza di faults e studiarne poi le eventuali reazioni ad
essi.
Le tecniche di Software Fault Injection sono sostanzialmente due: una che inietta i guasti
direttamente sul codice binario, detta G-SWFIT (Generic Software Fault Injection
Technique), e una che simula i guasti iniettandoli direttamente nel codice sorgente del
programma, detta Source Code Fault Injection (SCFI).
In un primo momento, la Software Fault Injection era vista come una fase successiva al
rilascio del determinato prodotto software. Infatti avveniva dapprima un‟analisi e
classificazione dei vari fault che si manifestavano durante la vita del programma e solo in
una fase successiva si effettuava l‟iniezione dei guasti che si sono verificati più
frequentemente, in modo da eseguire un‟analisi mirata degli stessi. Inutile sottolineare che
questo tipo di approccio comportava tempi molto lunghi e non era quasi mai possibile
effettuare una fault injection durante la fase di sviluppo. Per questo motivo sono stati
portati avanti svariati studi con lo scopo di generalizzare il problema, al fine di rendere
possibile di effettuare campagne di software fault injection mirate senza la necessità di
studi preventivi sul particolare prodotto o sistema in oggetto.
Innanzitutto è stato introdotto un sistema di classificazione dei tipi di software fault, la
Ortogonal Defect Classification (ODC) [12], con la quale si sono classificati in 6 categorie
i tipi di guasto (fault type):
-
Assignment : errata o mancata assegnazione dei valori;
-
Checking : mancata o errata validazione di dati o parametri utilizzati in istruzioni
condizionali;
-
Algorithm : problemi di efficienza o mancanza di correttezza di determinate
procedure, questo può essere risolto semplicemente reimplementando l‟algoritmo o
la struttura dati affetta;
-
Timing/Serialization : errata sincronizzazione tra sistemi/sottosistemi, moduli,
49
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
software/hardware, e/o mancata o incorretta serializzazione nell‟utilizzo di risorse
condivise;
-
Interface : problemi di comunicazione tra sottosistemi, moduli, componenti, sistemi
operativi o device drivers;
-
Function : errata o incompleta implementazione di una determinata funzione.
Ad ogni guasto corrisponde un fault trigger, ossia un evento durante il quale esso
avviene, classificabile secondo ODC in una delle seguenti 5 categorie:
-
Startup/Restart : fase successiva ad uno shutdown o fallimento nella quale il sistema
viene inizializzato o riavviato;
-
Workload volume/Stress : fase in cui il sistema effettua grandi volumi di operazioni
sfruttando al limite tutte le sue risorse;
-
Recovery/Exception : il guasto è stato innescato in quanto era attivo un gestore di
eccezioni o una procedura di recupero, quindi è stato causato da un fault precedente;
-
Hardware/Software configuration : fault innescato da una configurazione del sistema
non prevista o inusuale;
-
Normal mode : non è presente nessuna condizione particolare del sistema per far
innescare quel determinato guasto.
Studi statistici effettuati su un largo campione di sistemi software reali [13] hanno
permesso di capire come le sei categorie di fault type si distribuiscono, e hanno condotto
ad un‟estensione della classificazione ODC, con la creazione di 3 macrocategorie,
Costrutto mancante (Missing construct), Costrutto errato (Wrong construct) e Costrutto
estraneo (Extraneous construct); in particolare si è potuto evincere che i faults
appartenenti alle prime due macrocategorie ricorrono nel 98% dei casi.
50
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
3.2.1 Fault Injection Operators
Per i missing e i wrong constructs, in base a quest‟ultima classificazione, sono stati
definiti, nell‟ambito della tecnica G-SWIFT, altri tipi di guasto specifici, i fault specific
types, e i relativi Fault Injection Operators [13], ossia gli operatori di guasto che
descrivono il modo in cui vengono rilevate le parti di codice da dover modificare e
l‟insieme di regole e vincoli da seguire per effettuare il relativo fault injeciton. Vale la
pena di rivolgere l‟attenzione soprattutto ai principali, ossia ai 13 di essi che da soli
ricoprono più del 50% dei fault riscontrati nei sistemi reali:
-
OMFC (Operator for Missing Function Call): individua le chiamate a funzione in un
blocco di istruzioni e ne simula l‟omissione.
-
OMVIV (Operator for Missing Variable Initialization whit a Value): simula
l‟omissione delle inizializzazioni di variabili locali con valori costanti.
-
OMVAV (Operator for Missing Variable Assignment with a Value): Individua le
assegnazioni a variabili con valori costanti e ne simula l‟omissione.
-
OMVAE (Operator for Missing Variable Assignment with an Expression): individua
le assegnazioni a variabili tramite risultato di espressioni e ne simula l‟omissione.
-
OMIA (Operator for Missing IF Around statements): riproduce l‟omissione di una
condizione if che racchiude un insieme di istruzioni (o statements).
-
OMIFS (Operator for Missing IF construct and surrounded Statements): emula la
mancanza di un costrutto if e di tutto il suo contenuto.
-
OMIEB (Operator for Missing IF construct plus statements plus ELSE Before
statement): emula l‟omissione del costrutto if, degli statements al suo interno, e del
costrutto else associato.
-
OMLAC (Operator forMissing “AND sub-expression” in Logical expression used in
branch Condition): Omette una parte dell‟espressione logica utilizzata per un salto
51
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
condizionato. Tale espressione deve essere composta da almeno due sotto-espressioni
collegate tra loro per mezzo dell‟operatore AND.
-
OMLOC (Operator for Missing “OR sub-expression” in Logical expression used in
branch Condition): omette una parte dell‟espressione logica utilizzata per un salto
condizionato. Tale espressione deve essere composta da almeno due sotto-espressioni
collegate tra loro per mezzo dell‟operatore OR.
-
OMLPA (Operator for Missing Localized Part of the Algorithm): riproduce
l‟omissione di una parte, piccola e localizzata, dell‟algoritmo
-
OWVAV (Operator for Wrong Value Assigned to a Variable): emula una
assegnazione ad una variabile con un valore errato. Per evitare i problemi dovuti al
calcolo random, il valore errato viene scelto semplicemente invertendo i bit meno
significativi del valore effettivamente utilizzato.
-
OWPFV (Operator for Wrong Variable in parameter of Function call): emula
l‟utilizzo della variabile sbagliata come parametro in una chiamata a funzione.
-
OWAEP (Operator for Wrong Arithmetic Expression in Parameter of a function
call): emula il guasto che consiste nell‟avere una espressione aritmetica errata
utilizzata come parametro ad una chiamata a funzione.
3.2.2 Tool per la Software Fault Injection
Il tool di fault injection utilizzato nel presente lavoro di tesi, nella campagna sperimentale
del caso di studio che sarà preso in esame nel Capitolo 4, è un tool preesistente, un
prototipo [15] [14], sviluppato appositamente per automatizzare le operazioni di iniezione
guasti all‟interno di un sistema software. Esso utilizza gli stessi fault operators appena
illustrati, ma la tecnica di iniezione adottata è la Source Code Fault Injection, che come già
detto si differenzia per il momento dell'iniezione: al fine di determinare le possibili fault
location, piuttosto che ispezionare il codice binario nella ricerca di pattern relativi a sezioni
52
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
di codice opportune, viene ispezionato direttamente il codice sorgente, che, una volta
determinati i fault, viene modificato mediante i fault operators. Ovviamente tale tecnica
necessita del codice sorgente dell'applicazione, cosa che non accade per la tecnica GSWFIT ma, a differenza di quest‟ultimo approccio, ha il vantaggio di superare una serie di
problemi di accuratezza e di corrispondenza tra le modifiche agli eseguibili e i fault che
rappresentano. Questo vantaggio ha il costo di un aumento del tempo necessario alla
generazione delle varianti faulty del sistema, poiché si rende necessaria una separata
ricompilazione del codice per ogni fault da iniettare.
In particolare, il tool in questione può essere utilizzato su software i cui sorgenti sono
codificati in linguaggio C/C++. Per effettuare la software fault emulation, come prima
cosa, il tool injector si occupa di effettuare delle analisi statiche sul programma in esame e
dai risultati costruisce un Abstract Syntax Tree, struttura dati che rappresenta il codice
sorgente analizzato. Successivamente applica in modo automatico i vari fault injection
operators per trovare le aree di codice dove effettuare l‟iniezione dei guasti ed infine crea
un insieme di patch, ognuna corrispondente ad un fault. I file .patch contengono, infatti, le
istruzioni necessarie per modificare, secondo l‟operatore utilizzato, il codice sorgente
analizzato per iniettarvi il guasto.
Lo schema in figura descrive il processo di esecuzione del tool.
Esso attualmente è eseguibile in ambiente Linux, e finora è stato usato con successo con
svariati sistemi software il cui codice sorgente è in linguaggio C/C++, come il Web Server
Apache, MySQL DBMS, e i sistemi operativi Linux e RTEMS. Inoltre, il codice faulty da
esso generato è platform-indipendent, e cioè può essere compilato tranquillamente senza
necessariamente dover disporre del codice sorgente del sistema originale.
53
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
3.3 Monitor FFDA
E‟ stato già specificato che, per rendere il sistema software faulty tramite la Source Code
Fault Injection, è necessario disporre del suo codice sorgente. Ciò facilita anche un‟altra
operazione, necessaria affinché esso possa loggare sul logbus-ng i messaggi di log
secondo le regole stabilite: il software deve essere “instrumentato”, per comportarsi
appunto da FFDALogger. A tal fine vengono utilizzati i meccanismi messi a disposizione
dalla API lato sorgente già descritta nel precedente capitolo: includendo la corrispondente
libreria nei propri riferimenti, e costruendo un‟istanza della classe FFDALogger,
l‟applicazione in questione avrà a disposizione i metodi per loggare sul Logbus-ng i Life
Cycle Events e gli Interaction Events. A questo punto, il sistema software faulty ed
instrumentato, sottoposto ad un carico di lavoro, produce una serie di messaggi legati a tali
eventi, inoltrandoli sul Logbus-ng e da lì ad un qualsiasi monitor interessato a riceverli.
Con le API lato client è stata quindi realizzata l‟applicazione monitor del framework,
ossia un tool creato ad hoc per:
-
Sincronizzarsi con il Testbed Manager, e quindi con il software sotto test e tutte le
altre entità attive nel framework.
-
Ricevere di volta in volta i messaggi dal Logbus-ng, sollevando i corrispondenti alert
qualora non fossero rispettate le regole di logging.
-
Creare per ogni test un corrispondente file di log.
-
Gestire la durata degli intervalli di tempo oltre i quali sollevare gli alert.
-
Gestire eventuali eccezioni sollevate dal Logbus-ng o dalle sue API, in modo tale da
impedire, in tali casi, l‟arresto della campagna di test e recuperare gli eventuali test
perduti.
La sua interfaccia richiama quella di uno dei monitor FFDA realizzati nell‟ambito di
[10], funzionando in ambiente Microsoft Windows (sfruttando le librerie del .NET
FrameWork 3.5), e ingloba molte delle sue funzionalità, tra le quali di particolare rilievo è
54
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
una form in cui poter scegliere le entità da monitorare in base a dei filtri standard o
personalizzati, o selezionandola da un‟apposita lista fornita dall‟EntityPlugin. Una volta
scelte le entità da monitorare, o comunque i filtri con cui scremare i messaggi in arrivo dal
Logbus, si può visualizzare il resoconto generale mediante una tabella riassuntiva dello
stato generale del sistema in analisi. In questa tabella vengono riportati tutti gli eventi di
ogni singola entità monitorata, comprese le marche temporali e gli heartbeat, inoltre, in
caso di anomalie (anche temporanee) sono visualizzati tutti i messaggi di alert in accordo
alle regole descritte nel secondo capitolo.
Gli intervalli per gli alert e gli heartbeat sono stati parametrizzati, in modo da permettere
facilmente il loro settaggio (anche real time durante l‟esecuzione dei test), senza dover
intervenire sul codice sorgente. Ciò può essere utile a regolare il monitor in presenza di
ritardi, magari dovuti a particolari condizioni di traffico o all‟architettura stessa della rete,
riducendo la produzione di “falsi positivi”: un intervallo di tempo troppo ristretto per le
condizioni della rete sulla quale è appoggiato il logbus potrebbe portare a segnalazioni di
alert dovute alla mancata consegna entro il tempo limite di un messaggio di END, pur
essendo stato loggato dall‟applicazione sul lato sorgente. Modulare tali intervalli di tempo
potrebbe anche risultare utile per svolgere test più specifici, nei quali ad esempio si
potrebbe avere la necessità di escludere le segnalazioni per mancati Heartbeat
(PING_FAILED), o vicerversa degli Alert, o per test mirati a valutare le prestazioni sulla
rete del logbus stesso.
Quando il monitor rileva una o più anomalie, esso le segnala modificando coerentemente
lo stato delle entità (ultima colonna sulla destra), provvedendo a colorare la riga della
tabella in base alla tipologia di alert; anche per questo tipo di segnalazione si è deciso di
seguire la convenzione usata in monitor precedentemente realizzati, e cioè:
-
Rosso: per segnalare la presenza di uno o più messaggi di COA.
-
Giallo: per segnalare la presenza di uno o più messaggi di EIA
-
Verde: per segnalare la presenza di uno o più messaggi di RIA.
55
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
-
Viola: per segnalare la presenza di uno o più messaggi di CMP.
-
Blu: per segnalare la presenza di uno o più messaggi di MISS (perdita di uno o più
pacchetti sulla rete).
-
Arancione: per segnalare la presenza di uno o più messaggi di PING_FAILED (nel
caso in cui non si riceva l‟heartbeat di un‟entità entro il timeout fissato).
Ogni segnalazione di alert viene riportata nel corrispondente file di log, un file di testo
denominato FFDA.log, che non è altro che un Report Rule-Based, nel quale vengono
riportati, rifacendosi allo standard Syslog definito in precedenza, una serie di
informazioni, come data e ora, l‟entità che ha provocato l‟alert e il tipo di alert stesso.
Come si può notare dal testo riportato qui come esempio, il file FFDA.log molto semplice
da consultare in quanto privo di tutti gli eventi superflui e contenente solo le entry di alert
delle singole entità monitorate;
gli unici messaggi connessi ad un comportamento
“normale” delle entità che sono ammessi, sono quelli relativi agli eventi di StartUp (SUP).
<134>1 2011-11-30T22:07:44+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_main SUP
<134>1 2011-11-30T22:07:44+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_vhost SUP
<134>1 2011-11-30T22:07:44+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_protocol SUP
<134>1 2011-11-30T22:07:44+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_config SUP
<134>1 2011-11-30T22:07:44+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_request SUP
<134>1 2011-11-30T22:07:44+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_core SUP
<129>1 2011-11-30T22:07:51+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_config COA
<129>1 2011-11-30T22:07:51+01:00 - MonitorFFDA - FFDA - Entity: linux-uoyn-http_main EIA
Dal testo dello specifico file riportato in esempio, si nota subito che, dopo aver loggato i
classici messaggi di StartUp, una delle entità monitorate, linux-uoyn-http_config, ha
loggato sul bus un evento di SST al quale non è seguito un SEN, provocando da parte del
monitor la segnalazione di un Computation Alert (COA).
56
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
3.3.1 Sincronizzazione del Monitor FFDA
Le operazioni appena descritte rientrano nel meccanismo di comunicazione tra
applicazione e monitor tramite Logbus-ng, rivolto ovviamente alla raccolta e trasmissione
dei messaggi di log. In una campagna composta da migliaia di test, che quindi deve essere
automatizzata, è necessario un altro meccanismo di comunicazione, tra il Testbed Manager
e il monitor che funge da alert detector, in modo tale che quest‟ultimo possa ricevere degli
avvisi su quando un singolo test comincia, quando termina, quando riparte il test
successivo, predisponendo e/o eseguendo le operazioni del caso.
Non potendo, per ovvi motivi, utilizzare i canali del logbus, che sono demandati ad altre
funzioni, si è optato per far comunicare Testbed Manager e il monitor tramite un socket
TCP. Tale scelta è anche conseguenza del fatto che, come si vedrà, il Testbed Manager è
realizzato in ambiente Linux, mentre il monitor, essendo realizzato utilizzando a API
sviluppate in C# sul .NET Framework 3.5 della Microsoft, funziona in ambiente
Windows. Ciò, più che un freno, è stata considerata un‟occasione per aumentare la
portability del framework, fornendo al tool un supporto di comunicazione universale,
come è appunto il socket TCP.
Il funzionamento è abbastanza semplice: all‟avvio dell‟applicazione monitor, viene
avviato un thread in background demandato alla creazione del socket e all‟ascolto su di
esso. I due snippet di codice seguenti corrispondono a tali operazioni: il primo è presente
nel costruttore della MainForm del programma monitor, e serve per l‟appunto ad istanziare
e avviare il thread, richiamando la funzione WaitForTBMessage, che è mostrata nel
secondo.
// start Listening Thread:
new Thread(new ThreadStart(this.WaitForTBMessage))
{
IsBackground = true,
}.Start();
57
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
private void WaitForTBMessage()
{
try
{
System.Net.Sockets.TcpListener listener = new System.Net.Sockets.TcpListener(
new IPEndPoint(IPAddress.Any, 4999));
// Inizialize a TCPListener
listener.Start();
while (true)
{
if (listener.Pending())
{
string message = "";
System.Net.Sockets.TcpClient localClient = listener.AcceptTcpClient();
System.Net.Sockets.NetworkStream netStream = localClient.GetStream();
if (netStream.CanRead)
{
System.IO.MemoryStream dataStream = new System.IO.MemoryStream();
int byteRead = 0;
byte[] buffer = new byte[30];
if ((byteRead = netStream.Read(buffer, 0, 25)) > 0)
{
dataStream.Write(buffer, 0, byteRead);
message += System.Text.Encoding.ASCII.GetString(buffer,0,byteRead);
}
switch (message)
{
case "REFRESH":
btnClearAlert.PerformClick();
break;
case "RESTART":
ClearLogs();
Restart();
break;
default:
this.current_test = message;
MoveLogFile(message);
break;
}
}
}
}
}
catch (Exception ex)
{
Global.WriteExceptionLog(ex);
}
}
private void MoveLogFile(string folder_name)
{
System.IO.Directory.CreateDirectory(folder_name);
System.IO.File.Copy("FFDA.log", folder_name + "\\FFDA.log",true);
}
58
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Il metodo WaitForTBMessage si occupa innanzitutto di creare un‟istanza della classe
TcpListener, del namespace System.Net.Sockets, di inizializzarla, specificandone la porta e
gli indirizzi IP da “ascoltare”, e di porla all‟ascolto. Di default si è deciso di usare la porta
4999, e di accettare sul socket le connessioni in ingresso da parte di qualsiasi indirizzo IP.
Quando viene ricevuto un messaggio, esso viene posto in un array di byte e quindi
convertito in una sequenza di caratteri ASCII. I messaggi gestiti sono della lunghezza
massima di 25 caratteri, e di 3 tipi:
-
Il nome del test eseguito (considerato caso di default nello switch(message)): questo,
come si vedrà in seguito, indica che il test x è terminato e quindi il suo log va salvato.
Ciò viene fatto richiamando un metodo che non fa altro che spostare il file
FFDA.log, sul quale il monitor ha scritto fino a quel momento, in una cartella che ha
lo stesso nome del test in questione:
-
Un messaggio di RESTART, inviato dal TestBed Manager subito prima dell‟avvio di
un nuovo test, per permettere al monitor di resettare il file di log (tramite due
semplici operazioni di Delete e Create all‟interno di un Lock per la scrittura sul file,
acquisito per evitare che ci siano scritture concorrenti, da parte del monitor, sul file
stesso), cancellare tutti gli alert e i messaggi di log eventualmente ancora presenti
nella sua coda, eseguire un refresh della tabella e, soprattutto, istanziare un nuovo
channel sul logbus per la ricezione dei messaggi di log relativi al test successivo,
tramite la funzione AddClient.
-
Infine, è previsto un opzionale messaggio di “REFRESH”, utilizzabile qualora si
voglia semplicemente eseguire una pulizia della tabella e degli eventi in coda al
monitor.
59
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
private void ClearLogs()
{
// Reset LogFile
this.Lock.AcquireWriterLock(500);
try
{
System.IO.File.Delete("FFDA.log");
System.IO.File.Create("FFDA.log");
}
catch (Exception ex)
{
Global.WriteExceptionLog("ClearLogs Exception near test "+ this.current_test);
Global.WriteExceptionLog(ex);
}
finally
{
this.Lock.ReleaseWriterLock();
}
}
private void Restart()
{
try
{
AddClient(this.Filter);
btnClearAlert.PerformClick(); // Refresh grid
}
catch (Exception ex)
{
Global.WriteExceptionLog("Restart Exception near test " +this.current_test);
Global.WriteExceptionLog(ex);
}
}
Grazie a tale sistema di comunicazione è quindi possibile gestire un arresto e una ripresa
“a caldo” del monitor, evitando di dover arrestare e riavviare da capo il tool ad ogni test,
operazione che comporterebbe uno spreco notevole di tempo: basti pensare che l‟avvio del
tool richiede, a seconda delle prestazioni della macchina sulla quale gira, dai 15 ai 30
secondi per un avvio, dovendo caricare le librerie del .NET FrameWork necessarie al suo
funzionamento; un ritardo del genere ad ogni test non è ovviamente tollerabile, se si
intende eseguire lunghe campagne composte da migliaia di esperimenti. Del resto, anche
volendo eseguire lo stop e riavvio a freddo del tool, sarebbe comunque necessario un
meccanismo di comunicazione tra il testbed manager Linux e il tool su Windows di eguale
60
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
complessità, e quindi non permetterebbe in ogni caso di semplificare l‟architettura
necessaria a far interagire le due piattaforme.
C‟è da sottolineare, infine, che le API utilizzate dal monitor, e lo stesso Logbus-ng, non
sono finora stati testati nell‟ambito di lunghe campagne di testing, comprendenti quindi
una notevole quantità di arresti e riavvii delle applicazioni coinvolte; del resto, il
framework realizzato nel presente lavoro di tesi, è la prima architettura software a
coinvolgere il Logbus-ng e le sue API nell‟ambito di campagne del genere, volte a
valutare e perfezionare sistemi software e relativi meccanismi di logging.
Pertanto, come si è già intravisto negli snippet di codice riportati in precedenza, le
eccezioni, eventualmente sollevate durante la fase di arresto e ripresa a caldo del monitor,
sono state catturate e loggate su file, tramite un‟apposita classe statica Global:
public static class Global
{
public static void WriteExceptionLog(Exception ex)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(
@"FFDAGUI_ExceptionLog.txt", true);
string log = DateTime.Now.ToShortDateString() + " " +
DateTime.Now.ToLongTimeString() + " - " + ex.ToString() + System.Environment.NewLine;
file.WriteLine(log);
file.Close();
file.Dispose();
}
public static void WriteExceptionLog(string ex)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(
@"FFDAGUI_ExceptionLog.txt", true);
string log = DateTime.Now.ToShortDateString() + " " +
DateTime.Now.ToLongTimeString() + " - " + ex + System.Environment.NewLine;
file.WriteLine(log);
file.Close();
file.Dispose();
}
}
Qualora venga sollevata un‟eccezione, il tool non viene arrestato, evitando quindi che
l‟intera campagna di test debba arrestarsi, ma viene riportato il testo dell‟eccezione nel file
FFDAGUI_ExceptionLog.txt, con lo stacktrace e, soprattutto, il nome del test durante il
quale è avvenuto l‟errore. Ciò permette di continuare la campagna senza problemi anche
in caso di errore, al costo di un singolo test che viene con ogni probabiltà “sporcato”, il cui
61
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
nome viene tuttavia riportato nell‟ExceptionLog in modo da poter essere poi
tranquillamente recuperato. Il formato del file è descritto dal seguente esempio,
corrispondente al report
di un‟eccezione sollevata in concomitanza del test
http_protocol.i_OMLPA_450 (per una maggiore leggibilità, non si riporta lo stacktrace):
19/11/2011 22:46:10 - AddClient Exception near test http_protocol.i_OMLPA_450
… … [ STACKTRACE ] … …
3.4 Testbed Manager
I componenti del framework descritti finora sono tutti demandati a svolgere operazioni
ben precise e ben definite, volte alla data logging and collection durante una singola
esecuzione del software, ossia durante un singolo esperimento. Ovviamente, per poter
validare appieno il meccanismo di logging in esame, è necessaria una campagna per la
raccolta di log consistente in una (lunga) serie di test, ognuno dei quali coinvolge una
versione faulty del software in esame. A tal fine risulta indispensabile un‟entità software
in grado di supervisionare ed automatizzare gli esperimenti della campagna, coordinando
di volta in volta tutti i vari componenti facenti parte dell‟ambiente software in cui essa
viene svolta.
Nel framework realizzato nel presente lavoro di tesi, tali operazioni sono svolte da un
“Testbed Manager” o (Test Manager), una piccola applicazione consistente in un bash
Linux, che funge da coordinator degli esperimenti, assicurandosi di eseguire
automaticamente tutti i test di cui la campagna è composta. In particolare, per ognuno di
essi, si occupa di:
-
Tener traccia, in una lista, degli test eseguiti fino a quel momento, e quelli ancora da
eseguire. Ciò permette in qualunque momento di stoppare e riavviare le operazioni,
nonché di modificare la lista degli esperimenti da eseguire.
62
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
-
Esegure un clean up preventivo delle risorse (come, ad esempio, processi zombie,
semafori non allocati), in modo da permettere che ogni singolo test avvenga nelle
medesime condizioni operative dei precedenti.
-
Gestire la comunicazione con il demone del Logbus-ng, il “LogbusDaemon”,
avviandolo e stoppandolo a seconda delle esigenze.
-
Gestire la comunicazione con il Monitor FFDA, per ordinarne il riavvio e/o il
salvataggio dei log FFDA, secondo le tecniche già illustrate nei paragrafi precedenti.
-
Inizializzare e avviare la versione faulty del software corrispondente al test corrente.
-
Gestire la comunicazione con il Workload Generator, salvandone l‟esito.
-
Determinare l‟esito dell‟esperimento appena compiuto, fungendo quindi anche da
„oracolo‟, e salvarlo su file.
-
Salvare tutte le informazioni raccolte in relazione al test eseguito in una cartella
denominata con suo stesso nome.
Il fatto che tale applicazione sia scritta in bash, ne favorisce, tra l‟altro, l‟editing e quindi
l‟integrazione di componenti di codice personalizzato, necessarie per l‟avvio delle
applicazioni “custom” del framework e per la comunicazione con esse.
3.4.1 Meccanismi di comunicazione
Vale la pena soffermarsi un attimo sui meccanismi di comunicazione utilizzati dal
Testbed Manager, essendo esso l‟applicazione che a tutti gli effetti “pilota” il framework
durante una campagna di test.
Nel descrivere il monitor FFDA si è fatto riferimento al canale di comunicazione tramite
socket TCP creato appositamente per ricevere i “comandi”, descrivendo come è stato
realizzato, utilizzando il linguaggio C# e le librerie del .NET Framework 3.5, il thread per
l‟ascolto e la ricezione dei messaggi. Ovviamente, anche lato testbed manager è stata
63
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
realizzata una struttura analoga, e cioè un socket TCP per l‟invio di messaggi, utilizzando
gli strumenti a disposizione su piattaforma Linux: linguaggio e librerie C. E‟ stato quindi
creato un eseguibile, send_socket_msg, in grado di:
-
Creare e istanziare un socket TCP su una porta predefinita
-
Inviare tramite esso un messaggio (una stringa di caratteri) verso un indirizzo IP e
una porta specificati.
-
Chiudere ed eliminare il socket creato.
Si riportano brevemente gli snippet del codice sorgente di “send_socket_msg” inerenti
alle 3 operazioni appena descritte:
// Create the TCP socket:
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
printf("socket creation failed.\n");
return 0;
}
// Construct the server sockaddr_in structure:
memset(&sad, 0, sizeof(sad));
// Clear struct
sad.sin_family = AF_INET;
// Internet/IP
sad.sin_addr.s_addr = inet_addr(argv[1]);
// IP address
sad.sin_port = htons(port);
// server port
// Establish connection:
if (connect(sock, (struct sockaddr *)&sad, sizeof(sad)) < 0)
{
printf( "Failed to connect.\n" );
close(sock);
return 0;
}
else
{
printf("\nConnected to FFDA_Monitor\n");
}
// Send message to server:
int stringLen = strlen(inputString); // Determina la lunghezza
if (send(sock, inputString, stringLen, 0) != stringLen)
{
printf("send() sent a different number of bytes than expected");
close(sock);
return 0;
}
printf ("Message to FFDA_Monitor sent: %s\n", inputString);
64
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
// Close Socket:
close(sock);
Altro tipo di comunicazione disponibile, è quella esistente tra la macchina sulla quale è
in esecuzione il testbed manager e quella sulla quale è presente il Logbus-ng. Come già
accennato, quest‟ultimo rappresenta una parte “platform-indipendent” del framework che
si è deciso di hostare in un ambiente Linux, così come il testbed manager che, come si
vedrà a breve, ha necessità di comunicare con il Logbus-ng unicamente per inviare
semplici comandi per l‟avvio e l‟arresto del suo demone. Ciò ha permesso l‟utilizzo di un
sistema di comunicazione tra le due macchine molto più semplice, tramite l‟interprete
Remote Shell (RSH). Quello del socket TCP è, infatti, un meccanismo di
implementazione sicuramente più complessa, perché richiede la creazione di un socket per
l‟invio di messaggi ed uno per l‟ascolto e la ricezione degli stessi, ossia uno sul lato client
e uno sul lato server; l‟invio di istruzioni tramite RSH richiede invece, in ambiente Linux,
solo delle semplici operazioni di configurazione (lato client e lato server), riportate in
appendice.
3.4.2 Funzionamento
Il funzionamento del Testbed manager consta in una serie di fasi, descritte dal flowchart
in figura.
Start Testbed Manager
Una volta avviato, il testbed manager si assicura che il LogbusDaemon e il monitor
FFDA siano avviati; in realtà tale sequenza non è rigida, nel senso che è possibile avviare
LogbusDaemon e monitor FFDA anche prima dell‟avvio del bash del testbed manager;
65
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
l‟importante è giungere all‟avvio del Test con entrambe le entità correttamente avviate.
Start Test
Prima di avviare il test, si procede al controllo di una serie di controlli, come la verifica
dello spazio libero su disco, nonché ad una serie di operazioni volte a permettere che
l‟esperimento avvenga nelle medesime condizioni operative dei precedenti (come il clean
up di processi zombie, semafori non allocati, o, eventualmente, particolari operazioni
legate alla specifica natura dell‟applicazione software sotto test).
Dopodiché si effettua un check sulle liste dei test svolti e da svolgere, in modo da
66
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
identificare quello da eseguire al passo corrente; ovviamente, in assenza di ulteriori
esperimenti da eseguire, l‟algoritmo si arresta.
Start Faulty Target System (1)1
Individuato il test da eseguire, viene inizializzata e avviata la versione faulty del software
in esame. Questa parte è ovviamente “custom”, perché i comandi di inizializzazione e
avvio sono legati all‟applicazione da eseguire, al suo ambiente e al suo path, e quindi
vanno personalizzati nella fase di design del framework antecedente l‟avvio della
campagna. Per avviare l‟eseguibile dell‟applicazione, si può in ogni caso usare uno
qualsiasi degli strumenti di comunicazione che il framework mette a disposizione.
A questo punto è necessario verificare se il software faulty si è avviato: essendo presenti
in esso uno o più faults, è possibile che venga sollevato un failure già nella sua fase di
startup, provocandone un mancato avvio.
In caso di avvio, si passa alla fase di esecuzione del workload, altrimenti tale fase viene
saltata.
Run Workload (2)
Una volta completato l‟avvio del software, viene lanciato il corrispondente workload
generator, per sottoporre al sistema un carico di lavoro al fine di provocarne eventuali
fallimenti. Anche il comando di avvio del workload generator è “customizable”, essendo
anch‟esso un‟applicazione strettamente legata al sistema software che intende stressare.
Pertanto, anche il comando di avvio del generatore di workload e il workload stesso
vanno definiti nella fase di design del framework, fermo restando che anche per avviare
questa applicazione è possibile usare uno dei meccanismi di comunicazione messi a
disposizione.
1
Con i numeri indicati tra parentesi si fa riferimento allo schema del framework mostrato a pag.46
67
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Save Logs (3)
Indifferentemente se il workload sia stato eseguito o meno, vengono salvati gli eventuali
log prodotti dal sistema software in esame e dal suo workload generator.
Vengono inoltre salvati i log prodotti dal Monitor FFDA che, dalla fase di avvio del
software faulty, sta raccogliendo i vari messaggi inoltrati dal Logbus-ng, producendo gli
eventuali alert. Per comunicare al Monitor FFDA di salvare il file di log, il testbed
manager invia ad esso un messaggio tramite il socket TCP, specificando il nome del test
appena eseguito, usando l‟eseguibile send_socket_msg (nell‟esempio riportato di seguito il
Monitor FFDA si trova su una macchina con indirizzo IP 10.0.0.5, con socket in ascolto
sulla porta 4999):
./send_socket_msg 10.0.0.5 4999 $FAULT
Save oracle view
Il Testbed Manager agisce da failure detector, riportando l‟esito del test che salvato sul
file outcome.txt. Questa fase è fondamentale, dato che le tecniche e i tool di fault injection
appena descritti sono stati progettati e sviluppati con lo scopo di provocare facilmente
fallimenti di un sistema software posto sotto un carico di lavoro prestabilito, e risulta
pertanto di importanza cruciale disporre di strumenti in grado di rilevarli, con la massima
accuratezza possibile.
Per rilevare se è occorso o meno un fallimento, vengono sfruttate una serie di
informazioni derivate dall‟ambiente di testing, come dati generati dal sistema operativo
(ad esempio i memory dumps), informazioni specifiche derivate dal workload, il tempo di
risposta previsto. L‟uso congiunto di tali informazioni rende possibile identificare uno dei
seguenti esiti:
-
HALT: corrispondente in pratica al crash del sistema, ossia una sua imprevista
terminazione, dopo la quale esso non è più in esecuzione e quindi non produce più
alcun output
-
SILENT: corrispondente al caso in cui il sistema va in hang, ossia è ancora in
68
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
esecuzione ma senza produrre più alcun output, entro un ragionevole intervallo di
timeout.
-
CONTENT: il sistema solleva un failure, pur non andando in nessuna delle due
condizioni precedenti; è il caso di fallimento più comune, in cui l‟applicazione
fornisce all‟utente valori e/o servizi errati.
-
NO_FAILURE: in assenza di fallimenti.
In tal modo, il testbed manager agisce da “oracolo”, fornendo l‟effettivo esito
dell‟esperimento da comparare con le informazioni loggate nei vari file di log, nella fase di
Data Analysis successiva alla campagna di test.
Kill LogbusDaemon
Viene terminata l‟istanza attuale del demone del Logbus-ng, in modo da poterne usare
una nuova e pulita nel test successivo. Ciò avviene tramite l‟eseguibile kill_logbus.sh, che
richiama tramite RSH le istruzioni per invia alla macchina con il Logbus-ng i comandi per
killare l‟istanza del LogbusDaemon (che per comodità sono stati racchiusi nel bash file
killBus.sh presente nella root del LogbusDaemon).
#!/bin/bash
#kill_logbus.sh
rsh -l root 10.0.0.6 "/home/carlo/LogBus/logbus-sharp-2.3.42/Examples/killBus.sh"
Kill Target System
Viene terminata anche la versione corrente del software in esame (anche qui la tecnica
#killBus.sh
BUSPID=`ps aux | grep LogbusDaemon.exe | awk '{print $2}' | head -n 1`
kill -9 $BUSPID
per eseguire tale operazione rientra nella parte “custom” dello script).
69
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Si tenga presente che, in questa fase, il file FFDA.log prodotto dal Monitor FFDA è stato
già salvato e pertanto “messo in sicurezza” da eventuali messaggi, loggati sul bus a causa
del kill del processo demone e dell‟applicazione in esame, che non hanno alcuna valenza
al fine dell‟analisi e che piuttosto potrebbero inquinare i log del test appena avvenuto.
On LogbusDaemon
Viene quindi eseguito l‟avvio di una nuova istanza (pulita) del LogbusDaemon, tramite il
file on_logbus.sh, che non fa altro che inviare l‟istruzione d‟avvio alla macchina con il
Logbus-ng, tramite RSH.
#!/bin/bash
#on_logbus.sh
rsh -l root 10.0.0.6 "mono /home/carlo/LogBus/logbus-sharp-2.3.42/Examples/LogbusDaemon.exe >
/home/carlo/LogBus/logbus-sharp-2.3.42/Examples/logRemoto" &
echo "LogbusDaemon started"
Restart FFDA Monitor
Viene inviato al monitor FFDA il comando di “RESTART”, per predisporlo all‟inizio di
un nuovo test, secondo le operazioni già descritte nei paragrafi precedenti, sempre tramite
il socket TCP:
./send_socket_msg 10.0.0.5 4999 "RESTART"
Detto n il numero di test che si intende eseguire nella campagna, iterando l‟esecuzione di
questo script n volte, si otterranno alla fine n cartelle, ognuna con il nome di un test
eseguito, contenenti per ognuno di esso il corrispondente outcome dell‟oracolo, gli
eventuali di log che la versione faulty del sistema ha prodotto e del suo workload
generator, il file FFDA.log contentente le entry di log prodotte dall‟infrastruttura di
logging “Logbus-ng + MonitorFFDA”.
70
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Il sequence diagram in figura evidenzia la sequenza di interazioni che avvengono tra i
vari componenti del framework durante un singolo passo (esperimento) della campagna di
test:
71
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Da notare che i messaggi da e verso la “customizable area” sono volutamente generici
([System responce] è opportunamente considerato opzionale), perché ovviamente legati
alle particolari applicazioni software coinvolte.
In appendice è riportato, inoltre, l‟intero script del TestbedManager, comprendente anche
le istruzioni pilotare le operazioni relative al caso di studio che sarà analizzato nel
prossimo capitolo, quello sul Web Server Apache 1.3.41.
72
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Capitolo 4
Un caso di studio: Apache web server
L‟ultima fase del presente lavoro di tesi è incentrata sullo studio di un caso reale. In
particolare, si sono volute testare la funzionalità e l‟efficacia del framework realizzato,
nell‟ambito una lunga campagna di sperimentazione su un sistema di larga diffusione
quale è sicuramente il web server fornito dalla Apache Software Foundation [16], versione
1.3.41.
Come sarà spiegato a breve, il codice sorgente del web-server è stato innanzitutto
“instrumentato”, per permettergli di loggare gli eventi FFDA sul logbus-ng; sono state poi
create delle versioni faulty di esso, ognuna delle quali contentente un singolo fault; è stato
scelto un workload generator e definito un workload adatti a stressare il meccanismo di
logging di Apache, ossia l‟insieme di detector, istruzioni del codice, che mi permettono di
rilevare l'occorrenza degli errore (if errore... logga). E‟ stata infine eseguita una campagna
di test consistente in tanti esperimenti quanti sono state le versioni di Apache compilate.
L‟obiettivo è stato quello di ottenere un assessment del‟efficacia dei meccanismi di
logging rule-based, sui quali si fonda il framework realizzato, e del framework stesso,
tramite il benchmark con i tradizionali log prodotti da Apache, valutando cioè il grado di
copertura dei log di entrambi i sistemi, verificando cioè quanti (e quali) failure sono
riportati nei rispettivi log.
73
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
4.1 Instrumentazione del codice
Affinché il web-server Apache inoltrasse sul Logbus-ng tutti gli eventi di log descritti
dalle regole di logging, si è resa necessaria una fase preliminare di adattamento del codice
sorgente originale. Nel capitolo 2 sono già stati descritti i meccanismi messi a disposizione
dalla API per il lato sorgente del Logbus-ng, specificando come l‟agevole integrazione di
tale libreria con l‟applicazione in esame renda possibile la realizzazione di compilatori
instrumentanti, in grado di inserire nei punti cruciali del codice sorgente gli eventi di log,
sulla base delle regole definite nell‟approccio Rule-Based. In particolare si è già accennato
al fatto che la API lato sorgente preveda anche una (più snella) implementazione in
linguaggio C, per favorirne l‟integrazione su sistemi sviluppati in tale linguaggio, quale è
infatti Apache 1.3.41. L‟instrumentazione del codice di Apache, in modo che potesse
essere integrato con la API lato sorgente implementata in linguaggio C, è stata fatta
usando proprio tale implementazione.
Innanzitutto il codice sorgente è stato profilato mediante il software Gcov [17],
programma per la copertura dei test appartenente al progetto GCC [18], utile strumento
per l‟analisi del software al fine di creare codice più efficiente e individuare le sezioni non
testate; esso permette una profilazione del software, permettendo di valutare quali parti di
codice consumano la maggior parte delle risorse computazionali, grazie ad una serie di
statistiche, quali:
-
Quanto spesso una linea di codice viene eseguita
-
Quante linee di codice sono eseguite nello stesso istante
-
Quanto tempo di computazione richiede ogni sezione di codice
Nel caso in esame, il codice è stato compilato con dei flag speciali (-fprofile -arcs -ftest coverage); in seguito è stato eseguito il programma, creando in automatico dei file .gcda e
.gcno contenenti informazioni sul profile (lanciando il comando gcov –f nomefile.c è anche
74
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
possibile ottenere una versione facilmente interpretabile delle suddette informazioni). Alla
fine si ottiene un file nomefile.c.gcov, identico al sorgente nomefile.c, con delle info
aggiuntive. Nel presente caso di studio (Apache Web Server-1.3.41), sotto la directory
/src/main sono presenti i principali sorgenti; supponendo di voler modellare come entità
logiche solo alcuni di essi:
alloc.c
buff.c
gen_test_char.c
gen_uri_delims.c
http_config.c
 entità 0
http_core.c
 entità 1
http_log.c
http_main.c
 entità 2
http_protocol.c
 entità 3
http_request.c
 entità 4
http_vhost.c
 entità 5
rfc1413.c
util.c
util_date.c
util_md5.c
util_script.c
util_uri.c
Per ottenere i servizi che sono effettivamente invocati in una certa entità è sufficiente
prendere il relativo file gcov, estraendo le righe che hanno function called > 0 (basta fare il
cat del file, filtrare il risultato con una regular expression e stampare i nomi delle funzioni
con awk). Ad esempio, per http_config.c si prende http_config.c.gcov:
cat http_core.c.gcov | grep -e "function [^?]* called [1-9][0-9]*" | awk '{print $2}'
ap_make_array
ap_push_array
ap_make_table
ap_table_get
75
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
ap_table_setn
ap_register_cleanup_ex
ap_register_cleanup
ap_kill_cleanup
run_cleanups
…
Ripetendo questo procedimento per ogni entità, le funzioni ottenute saranno
instrumentate con le regole SST - SEN.
Per quanto riguarda le interazioni EIS – EIE, le informazioni necessarie sono: lista dei
servizi per ogni entità e sorgenti relativi ad ogni entità, per vedere se da questi parte
un‟invocazione verso un determinato servizio. Ad esempio, supponendo di voler capire se
l‟entità A (file: srcA.c, servizi s1_A, s2_A, s3_A) invoca qualche servizio di B (file:
srcB.c, servizi, s1_B, s2_B, s3_B), è necessario fare un cat/grep sul sorgente di A; in
questo modo, si riescono a ricavare tutte le interazioni cercate. Con pochi cicli innestati
che applicano quest‟esempio, si riescono a ricavare tutte le interazioni, ottenendo una
matrice delle interazioni, che nel caso in esame avrà la seguente forma:
Gli indici di riga e colonna rappresentano le entità, dove per “6” si è intesa un‟ipotetica
macro-entità rappresentante tutte le entità diverse da quelle prese in esame, ossia esterne al
modello, con le quali le entità da 0 a 5 interagiscono in qualche modo. Ovviamente le
interazioni relative alle prime cinque entità andranno in strumentate, mentre non è
necessario instrumentare le interazioni che dall‟esterno entrano nel modello, siccome
significherebbe instrumentare del codice esterno a quello d‟interesse, il che può risultare
del tutto impossibile nel caso di componenti proprietari o di servizi web remoti.
76
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Gli eventi SUP (start-up), sono stati collocati all‟avvio della funzione main del server
tanti messaggi quante sono le entità modellate come prima istruzione del programma, in
modo che fossero ragionevolmente i primi messaggi ad essere inviati al Logbus.
I messaggi di SDW (devono essere comunque sei), sono stati inseriti, come ultime
istruzioni, nella funzione handler del SIGTERM, ovvero quella che gestisce per conto
dell‟applicazione, il segnale di terminazione inviato dal sistema operativo (di fatto quello
scatenato quando si digita Ctrl+C sulla console). In questo modo si è sicuri che essi siano
inoltrati al Logbus-ng durante la fase di uscita “pulita” del programma (è evidente che un
segnale di SIGKILL non scatenerà l‟invio questi messaggi, rendendo così possibile la
simulazione di un fallimento per crash del server).
Per l‟invio dei messaggi HB di Heartbeath, sono stati creati sei thread distinti, ognuno
legato alla corrispondente entità, che in parallelo all‟esecuzione normale del software
provvedono ad inviare periodicamente al Logbus-ng i messaggi indicativi del loro stato
vitale.
Per completare il discorso, c‟è da dire che in questa instrumentazione non sono state
rilevate interazioni di entità con risorse del sistema da segnalare con i codici RIS - RIE, e
pertanto non sono stati inseriti i relativi eventi in nessuna riga di codice.
4.2 Fault Injection
Una volta instrumentate le sei entità, i file sorgenti di Apache sono stati sottoposti ad una
campagna di software fault injection, tramite l‟utilizzo del tool [15] descritto nel Capitolo
3: in essi sono stati iniettati dei faults, ossia delle modifiche in accordo ai 13 principali
operatori di fault injection citati. Il tool di SFI ha analizzato i sorgenti del web-server
(presenti nella cartella >src>main di Apache), producendo circa 11300 patch, ognuna delle
quali contenente le istruzioni necessarie per modificare il corrispondente file secondo le
direttive dello specifico operatore utilizzato. In particolare, per ogni fault, il codice è stato
77
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
compilato e la corrispondente versione faulty del web-server è stata salvata.
Ovviamente alcuni dei guasti iniettati non hanno permesso la compilazione del
programma, e quindi non tutte le 11300 compilazioni hanno avuto successo. In definitiva,
la campagna di sperimentazione è risultata composta da 8314 test, corrispondenti alle
versioni faulty di Apache ottenute, ognuna contentente un singolo fault, consistenti in
8314 versioni del file binario httpd, che riporta anche il nome dell‟esperimento.
La convenzione adottata prevede infatti che il nome della versione faulty, e quindi del
test, consista nel nome del file sorgente nel quale viene iniettato il guasto, più il nome del
fault operator utilizzato, ed un numero indicante quante volte esso è stato utilizzato sullo
stesso
file.
Ad
esempio,
il
test
“alloc.i_OMFC_0”
coinvolge
il
file
httpd_alloc.i_OMFC_0, che è il binario risultato dalla compilazione del codice sorgente
di apache, nel quale, in corrispondenza del file alloc.i è stato iniettato (per la prima volta,
da qui lo 0) un guasto secondo le direttive dell‟operatore OMFC (Operator for Missing
Function Call).
4.3 Workload
La fase successiva è stata la scelta del workload generator e la definizione del carico di
lavoro da sottoporre al sistema, in modo da stressarne i meccanismi di logging.
Il tool utilizzato per generare il carico di lavoro e sottoporlo al web-server Apache, è
stato Httperf [19], versione 0.9.0. Si tratta di un‟applicazione linux (disponibile in rete e
scaricabile sotto intermini della GNU Public License v2) che permette di simulare una
serie di connessioni al server e l‟invio di richieste http verso di esso, fornendo poi tutta una
serie di informazioni relative al suo comportamento in seguito a tali richieste, riassunte in
forma di statistiche e stampate alla fine di ogni simulazione.
Una volta scelto il tool, lo step successivo è stato quello di definire il workload da
sottoporre al web-server apache: ovviamente questo deve essere qualcosa in grado di
78
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
stressare il sistema e i suoi meccanismi di logging nella maniera più realistica possibile,
rispecchiando condizioni d‟uso realistico (cookie, estensioni di file e metodi diversi).
Un altro aspetto importante riguarda il “peso” di tale workload, ossia il numero di
richieste al secondo effettuate, al quale è necessariamente legata la durata dell‟elaborazione
del carico di lavoro da parte del web-server, che deve essere tenuta in stretta
considerazione, data la pressante esigenza di velocità del singolo esperimento: basti
pensare che, in una campagna di oltre 8000 test, ogni secondo speso per ogni test comporta
un aumento della durata complessiva di oltre due ore! E sottoporre al server troppe
richieste, allungando quindi i tempi di elaborazione da parte del sistema e aumentando la
quantità di log, rallentandone la raccolta, significherebbe accrescere notevolmente la durata
della campagna di test.
D‟altro canto non è neppure immaginabile sottoporre al web server un workload troppo
scarno, rischiando di non sollecitarlo abbastanza e quindi di andare incontro a possibili
falsi negativi, mancando un potenziale fallimento: quello dell‟efficienza in termini di
prestazioni, è pur sempre un requisito secondario del frame work per campagne di test
come questa, che deve sempre sottostare alla necessità di produrre assessments quanto più
precisi possibile.
Come trade-off tra le necessità di precisione e velocità, si è quindi optato per far simulare
ad httpef un workload al server consistente in 54 richieste.
L‟overhead introdotto dall‟instrumentazione del codice è stato volutamente ignorato,
considerando che la sperimentazione prodotta in [10] proprio su Apache 1.3.41, ha
confermato che, anche nelle peggiori condizioni dal punto di vista delle prestazioni
(trasporto TLS su memoria condivisa), il processo di log collection non inficia le normali
prestazioni del web server per un numero di richieste al secondo anche maggiore delle 54
decise per il workload.
L‟elenco delle richieste da sottoporre al web-server è stato salvato in un file,
workload.txt , richiamato da httperf ad ogni sua esecuzione: vengono richiesti, svariate
79
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
volte, con i metodi GET ed HEAD (il metodo POST non è supportato da httperf), 3 tipi di
file:
-
Un file html (Content-Type text/html)
-
Un documento pdf (Content-Type: application/pdf).
-
Un‟immagine jpeg (Content-Type: image/jpeg)
/mdr.htm method=GET headers='Content-Type: text/html \nCookie: test=00000\n'
contents='contenuto di prova'
/mdr.htm method=GET headers='Content-Type: text/html \nCookie: test=00000\n'
contents='contenuto di prova'
/doc.pdf method=GET headers='Content-Type: application/pdf \nCookie: test=00000\n'
contents='contenuto di prova'
/doc.pdf method=GET headers='Content-Type: application/pdf \nCookie: test=00000\n'
contents='contenuto di prova'
/rufy.jpeg method=GET headers='Content-Type: image/jpeg \nCookie: test=00000\n'
contents='contenuto di prova'
/rufy.jpeg method=GET headers='Content-Type: image/jpeg \nCookie: test=00000\n'
contents='contenuto di prova'
/mdr.htm method=HEAD headers='Content-Type: text/html \nCookie: test=00000\n'
contents='contenuto di prova'
/mdr.htm method=HEAD headers='Content-Type: text/html \nCookie: test=00000\n'
contents='contenuto di prova'
/doc.pdf method=HEAD headers='Content-Type: application/pdf \nCookie: test=00000\n'
contents='contenuto di prova'
/doc.pdf method=HEAD headers='Content-Type: application/pdf \nCookie: test=00000\n'
contents='contenuto di prova'
/rufy.jpeg method=HEAD headers='Content-Type: image/jpeg \nCookie: test=00000\n'
contents='contenuto di prova'
/rufy.jpeg method=HEAD headers='Content-Type: image/jpeg \nCookie: test=00000\n'
contents='contenuto di prova'
/mdr.htm method=GET headers='Content-Type: text/html \nCookie: test=00000\n'
contents='contenuto di prova'
/mdr.htm method=GET headers='Content-Type: text/html \nCookie: test=00000\n'
contents='contenuto di prova'
/doc.pdfdi
method=GET
headers='Content-Type: application/pdf \nCookie: test=00000\n'
4.4 Ambiente
test
contents='contenuto di prova'
/doc.pdf method=GET headers='Content-Type: application/pdf \nCookie: test=00000\n'
contents='contenuto di prova'
/rufy.jpeg
method=GET
headers='Content-Type:
image/jpeg
\nCookie:
test=00000\n'
Scelte
e definite
quelle
entità del framework
che nel
capitolo
3 erano state definite
contents='contenuto di prova'
“custom”,
ora possibile
definire meglio l‟architettura
del framework
/rufy.jpegè method=GET
headers='Content-Type:
image/jpeg \nCookie:
test=00000\n'utilizzata nella
contents='contenuto di prova'
presente sperimentazione. Sono stati già spiegati i motivi (perlopiù prestazionali) che
suggeriscono un ambiente di test nel quale Testbed Manager, Logbus-ng e Monitor FFDA
80
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
si trovino su tre macchine distinte (rispettivamente con sistemi Linux, Linux e Windows).
In esso sono state calate le altre due entità necessarie per tale sperimentazione, ossia il
web-server Apache e Httperf, assicurandosi che venissero eseguite su due macchine
distinte: se entrambe le applicazioni si trovassero sulla stessa macchina, Httperf invierebbe
delle richieste al web-server non da remoto, ma in localhost, non riproducendo quindi il
reale carico di lavoro al quale il web server è solitamente sottoposto.
Sfruttando anche il fatto che Apache e Httperf sono eseguibili in ambiente Linux, e che il
TestbedManager e Httperf hanno un impatto prestazionale minimo, si è potuto restringere
l‟architettura dell‟ambiente di test a 3 macchine, come mostrato nella seguente figura, che
evidenzia anche le linee di comunicazione tra i vari componenti del framework:
La configurazione ha previsto due macchine con Sistema Operativo Opensuse 11.3 [20],
e una con Microsoft Windows 7.
4.5 Esecuzione della campagna
La campagna è consistita in 8314 test. Prima di avviarla, sono state eseguite le
operazioni di customizzazione del Testbed Manager, necessarie ad avviare di volta in volta
la corrispondente versione faulty del web-server Apache e Httperf. Il flowchart del
capitolo 3 diviene quindi:
81
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Sono state evidenziate le parti relative alla “customizzazione” del Testbed Manager,
ossia quelle relative alle interazioni con il sistema software in esame (Apache) e il
workload generator (Httperf).
Install Faulty Web-Server
Viene copiato il binario faulty di apache, corrispondente al test in esecuzione, nella
cartella di esecuzione del web server (../apache_ws/bin/); vengono puliti gli eventuali file
di log lasciati dal test precedente.
82
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Run Faulty Web-Server
Il web server viene avviato.
Viene verificato se l‟avvio ha avuto successo.
Per i dettagli su tali operazioni si rimanda allo script riportato in Appendice
Run Httperf Workload
Se il web server si è correttamente avviato, viene invocato il bash file workload.sh per
sottoporvi un carico di lavoro:
#workload.sh
rsh 10.0.0.6 "cd / && cd home/carlo/httperf-0.9.0 && ./httperf -v --session-cookie --server=10.0.0.10
--port=8080 --hog --wsesslog=9,2,workload.txt --rate=2 --num-conns=18 --timeout=5"
Esso richiama, tramite RSH, l‟eseguibile ./httperf , presente su una macchina diversa da
quella sulla quale gira il web server, specificando, con una serie di opzioni
- Indirizzo IP e porta del web server (nel caso specifico 10.0.0.10:8080);
- Il numero di connessioni al server da simulare, con relativo timeout di attesa.
- Il file di testo dal quale prelevare l‟elenco delle richieste HTTP da sottoporre al server
(nel caso specifico workload.txt).
Httperf esegue le richieste contenute nel file workload.txt, producendo un output, utile
anche ai fini della determinazione dell‟esito del test da parte dell‟oracolo. Ne viene di
seguito riportato un esempio, nel quale si nota anche che, per questo particolare test di
carico, le 54 richieste sono state tutte servite, generando 54 risposte del server con codice
2xx (Success):
83
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
httperf --verbose --hog --timeout=5 --client=0/1 --server=10.0.0.10 --port=8080 --uri=/ --rate=2 -send-buffer=4096 --recv-buffer=16384 --session-cookies --wsesslog=9,2.000,workload.txt
httperf: maximum number of open descriptors = 1024
reply-rate = 3.4
session-rate = 0.0
reply-rate = 4.4
session-rate = 0.0
Maximum connect burst length: 1
Total: connections 9 requests 54 replies 54 test-duration 14.203 s
Connection rate: 0.6 conn/s (1578.1 ms/conn, <=9 concurrent connections)
Connection time [ms]: min 10071.2 avg 10232.7 max 10608.4 median 10190.5 stddev 173.5
Connection time [ms]: connect 0.0
Connection length [replies/conn]: 6.000
Request rate: 3.8 req/s (263.0 ms/req)
Request size [B]: 154.0
Reply rate [replies/s]: min 3.4 avg 3.9 max 4.4 stddev 0.7 (2 samples)
Reply time [ms]: response 15.2 transfer 18.0
Reply size [B]: header 234.0 content 61819.0 footer 0.0 (total 62053.0)
Reply status: 1xx=0 2xx=54 3xx=0 4xx=0 5xx=0
CPU time [s]: user 1.03 system 3.78 (user 7.2% system 26.6% total 33.8%)
Net I/O: 231.0 KB/s (1.9*10^6 bps)
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
Session rate [sess/s]: min 0.00 avg 0.63 max 0.00 stddev 0.00 (9/9)
Session: avg 1.00 connections/session
Session lifetime [s]: 10.2
Session failtime [s]: 0.0
Session length histogram: 0 0 0 0 0 0 9
Save Logs – Save Oracle view
Vengono salvati i file di log di apache (error_log, access_log, httpd.pid).
Viene riportato sul file outcome.txt l‟esito del test, valutato in base a diversi fattori, come
84
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
il report del workload, i core dumps, i timeout.
Per i dettagli su tali operazioni si rimanda allo script riportato in Appendice.
Kill Web-Server
Viene terminata l‟esecuzione del web server, uccidendo il relativo processo (httpd).
L‟operazione di kill viene eseguita più volte per assicurarsi che questa versione di Apache
non sia più in esecuzione durante il test successivo:
#kill_apache_all.sh
ping_pid=`/sbin/pidof httpd`
if [[ "$ping_pid" > 0 ]]
then
kill -9 $ping_pid
else
echo "Demon not found running!!!"
fi
ping_pid=`/sbin/pidof httpd`
if [[ "$ping_pid" > 0 ]]
then
kill -9 $ping_pid
else
echo "Demon not found running!!!"
fi
ping_pid=`/sbin/pidof httpd`
if [[ "$ping_pid" > 0 ]]
then
kill -9 $ping_pid
else
echo "Demon not found running!!!"
fi
85
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Andando quindi nello specifico, la sequenza di operazioni svolte ad ogni singolo
esperimento della campagna del presente caso di studio, può essere descritta dal
diagramma seguente:
86
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
4.5 Risultati
Vengono di seguito riportati i risultati ottenuti al termine della campagna di test.
Innanzitutto, degli 8314 esperimenti, 1106 (corrispondenti al 13,3 %) hanno riportato un
fallimento del sistema, mentre i rimanenti sono stati eseguiti correttamente, senza che
l‟oracolo ne riportasse errori.
I 1106 fallimenti sono risultati così distribuiti:
-
385 (34,81%) sono stati gli HALT, ossia i crash del web-server
-
133 (12,03%) i SILENT, corrispondenti alle volte in cui il web-server è andato in
hang
-
588 (53,16%) i rimanenti failure, segnalati come CONTENT
87
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
4.5.1 Benchmark Apache / Logbus-ng
Il meccanismo di logging di Apache ha riportato nei log 373 fallimenti, corrispondenti
ad una copertura del 33,73%:
Con particolare riferimento alle classi di fallimento, si notano altissime percentuali di
SILENT ed HALT non loggati, mentre c‟è una buona copertura (quasi il 60%) per gli altri
tipi di fallimento.
Con ogni probabilità ciò è dovuto all‟incapacità del log tradizionale ad evidenziare i
cosiddetti timing failures, e chiaramente, quando il web server va in crash o in hang, non
riesce a raggiungere quelle strutture di controllo che gli permetterebbero di produrre entry
nel file di log. Allo stesso tempo, sono altresì sterili le possibilità di rilevare nel log prove
di un crash o di un hang imminente. D‟altra parte, gli altri tipi di failures sono in buona
parte riportati, perché con ogni probabilità causati da errori nel codice che vengono
88
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
rilevati, e quindi loggati.
Il meccanismo di logging composto dal Logbus-ng + Monitor FFDA si dimostra, invece,
molto più efficace, con una copertura di 918 esperimenti, corrispondenti all‟ 83% :
con un‟alta copertura su tutte le classi di fallimento, anche (e soprattutto) su quelle per le
quali il meccanismo di logging di Apache si dimostra deficitario:
E‟ evidente come il meccanismo di logging utilizzato dal framework riesca a rilevare,
con grande frequenza, le occorrenze dei casi in cui il web-server non si avvia, crasha
improvvisamente, o rimane in hang.
In particolare viene rilevata un‟altissima percentuale di HALT, corrispondente in larga
parte a quei casi in cui il web-server ha loggato sul logbus, prima di crashare, gli eventi di
StartUp: l‟assenza dei corrispondenti eventi di ShutDown ha quindi permesso al
MonitorFFDA di rilevare immediatamente il failure.
89
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Riassumendo i dati relativi alla copertura di Apache e dell‟infrastruttura Logbus-ng, è
possibile visualizzare i fallimenti relativi a 4 classi:
-
Loggati sia da Logbus-ng che da Apache: 300 (27,12%)
-
Loggati solo dal Logbus-ng: 618 (55,88%)
-
Loggati solo da Apache: 73 (11,81%)
-
Non loggati: 115 (18,61%).
In particolare, le 4 classi si distribuiscono così sugli HALT e i SILENT:
HALT:
SILENT:
90
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Risulta evidente quanto più efficiente risulti il meccanismo di logging rule-based
attraverso il Logbus-ng: più della metà (55,88%) dei failure non sono stati rilevati da
Apache e, come prevedibile, gran parte di essi sono HALT e SILENT: ben 340 HALT
(88,31%) e 95 SILENT (71,43%) sono loggati unicamente dal Logbus-ng, contro i soli 3
HALT e i 10 SILENT loggati esclusivamente da Apache. Ciò dimostra quanto l‟approccio
rule-based sia molto più efficace soprattutto nei casi in cui il sistema va in crash o in hang.
Nel complesso, l‟apporto migliorativo effettivo è risultato essere di 545 failure (quasi il
50%) rilevati in più dal Logbus-ng rispetto il tradizionale logging di Apache.
91
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
4.5.2 Correlazione col workload
Investigando poi su come si distribuiscono i falures a seconda che il web server si sia
avviato correttamente, e cioè che il workload sia stato generato o meno, si nota che l‟avvio
di httperf è avvenuto all‟incirca nella metà dei casi:
Le classi di fallimento sono risultate così distribuite:
Web Server non avviato:
NO Workload
Web Server avviato:
Workload OK
Com‟era prevedibile la maggior parte delle volte (382, corrispondenti al 67%) in cui
l‟esecuzione del web-server non parte, la causa è l‟arresto improvviso (e quindi un HALT)
in fase di avvio.
Durante la fase operativa, invece, gli HALT sono molto rari, ed è più probabile che un
errore mandi il sistema in hang o ne provochi un fallimento di valore.
Andando ad analizzare come si comportano in entrambi i casi le due infrastrutture sotto
sperimentazione, risulterà ancora più evidente quanto il meccanismo classico di logging
sia strettamente correlato all‟esecuzione del web-server.
92
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Il primo caso, con il workload non avviato, si riferisce a tutte quelle volte in cui un
errore ha provocato un errore del sistema durante la sua fase di startup. Appare evidente
che Apache non riesca a riportare nei log quasi alcuna traccia dei problemi che ne hanno
causato il mancato avvio: come al solito, viene riportato qualche CONTENT, ascrivibile a
qualche fallimento di valore legato a qualche errore rilevato in tale fase, mentre non vi è
traccia dei casi in cui il sistema ha subito un arresto improvviso o sia andato in stallo.
Il Logbus-ng, invece, mantiene la sua solita copertura intorno all‟83%, e la sua solita
distribuzione sulle classi di fallimento:
93
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Nel caso in cui Apache si avvia correttamente, e quindi il workload viene avviato, anche
il suo me ccanismo di log diviene efficiente. La classe di fallimento più coperta è,
ovviamente quella dei CONTENT, mentre i 3 HALT presenti non sono stati loggati.
Il Logbus-ng anche in questo caso ha un comportamento perfettamente uniforme,
mantenendo le solite percentuali di copertura:
I 3 HALT accaduti durante l‟esecuzione del workload, inoltre, sono stati tutti rilevati.
94
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Conclusioni e sviluppi futuri
Il framework realizzato nel presente lavoro di tesi ha integrato appieno un'infrastruttura
di logging rule-based come il recente Logbus-ng, in particolari ambienti di testing, entro i
quali eseguire lunghe campagne di sperimentazione volte ad aumentare il grado di
dependability di un sistema software. I tool prodotti permettono infatti l'esecuzione
automatica di test su migliaia di versioni, rese appositamente faulty, di un'applicazione, al
fine di una più ampia, e soprattutto più efficace, “log and data collection”, secondo le più
moderne regole di logging, basate sui life-cycle events e gli interaction events.
I benchmark tra i dati raccolti con le classiche tecniche di logging e quelli raccolti
tramite l'approccio rule-based, che (come ha evidenziato il caso di studio preso in esame)
sono più precisi e completi, permettono quindi in fase di analisi di individuare le aree di
codice sulle quali intervenire per perfezionare sia il software in esame che il suo stesso
meccanismo di logging. In tal senso, il framework realizzato si configura come valido
strumento anche per l'assessment del meccanismo di logging di un sistema software in una
fase antecedente a quella operazionale, in modo da permetterne un miglioramento ancor
prima che esso entri nella piena fase operativa.
La campagna di sperimentazione svolta ha inoltre permesso di validare l'efficienza
dell'approccio al logging rule-based, confermando quanto esso si dimostri più efficace di
95
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
quello tradizionale. Il particolare caso di studio ha evidenziato quanto l'assenza dei lifecycle events e degli interaction events impedisca ad un sistema come Apache Web Server
di rilevare gran parte dei fallimenti, soprattutto quelli che ne causano l'arresto,
impedendogli di fatto di produrre entry nel file di log. Complessivamente, la copertura dei
fallimenti da parte di Apache è stata del 33%, contro l'83% raggiunto dal Logbus-ng.
Infatti, ben il 55% degli esperimenti terminati con un failure sono stati loggati
unicamente dall'infrastruttura “Logbus-ng + MonitorFFDA”, con percentuali ancor più
elevate per le classi di fallimento HALT e SILENT, per le quali il tradizionale
meccanismo di Apache si è dimostrato totalmente inadeguato.
Il framework realizzato si pone come supporto di partenza per validazione e/o
valutazione di meccanismi di logging su altri sistemi software, anche su piattaforme
complesse come middleware e sistemi operativi. A tal proposito risulterebbe utile la
realizzazione di tool per automatizzare il processo di instrumentazione del codice
sorgente, in modo da accelerare anche le fasi antecedenti la campagna di test vera e
propria.
La vasta di dati collezionabili tramite gli strumenti messi a disposizione dal framework
suggerisce inoltre di focalizzare l‟attenzione non solo verso analisi complessive sul
sistema in esame, ma anche verso analisi più precise, rivolte agli specifici alert riportati
nei file di log e ai particolari componenti che li hanno provocati, valutandone eventuali
correlazioni.
Infine, in riferimento a quei sistemi che si è cominciato o si vuole cominciare a dotare di
meccanismi di logging rule-based, e quindi instrumentare secondo tali regole, l'utilizzo del
framework può risultare utile per valutare la qualità (ossia il tasso di copertura) e il grado
(e quindi l'impatto prestazionale) dell'instrumentazione, per migliorare l'accuratezza dei
log prodotti, ed eventualmente ricercare un giusto trade-off tra prestazioni e precisione.
96
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Appendice A
Configurazione consigliata per il framework
Si riportano qui di seguito alcuni settaggi consigliati per far funzionare in maniera
ottimale alcuni componenti del Framework. Per i requisiti del Logbus-ng non riportati, è
possibile fare riferimento alla sua guida di riferimento [11].
Logbus Daemon:
-
Sistema Operativi supportati: Windows 7, Windows Server 2008, Linux (consigliato)
-
RAM: 1Gb
-
Framework/Pacchetti necessari:
- Windows: .NET Framework 4
- Linux: Mono 2.8, XSP Web Server
- Assicurarsi che il sistema abbia un network buffer di dimensioni abbastanza grandi
(almeno 4Mb), per evitare la perdita di messaggi di log.
Ad esempio, per aumentare le dimensioni del network buffer su sistemi operativi Linux
SUSE (ref:
http://www.susegeek.com/networking/network-performance-fine-tuning-in-opensuse-suse/),
modificare le seguenti linee del file “etc/sysctl.conf” come segue (configurazione usata
nella campagna di sperimentazione del capitolo4):
net.ipv4.tcp_reordering = 20
net.ipv4.tcp_wmem = 8192 87380 16777216
net.ipv4.tcp_rmem = 8192 87380 16777216
net.ipv4.tcp_no_metrics_save = 1
97
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
net.ipv4.tcp_congestion_control = cubic
net.core.wmem_max = 16777216
net.core.rmem_max = 16777216
Monitor FFDA:
-
Sistema Operativi supportati: Windows 7, Windows Server 2008, Windows XP SP3
-
RAM: 1Gb
-
Framework/Pacchetti necessari:- Windows: .NET Framework 4
-
Verificare che i performance counters funzionino correttamente:
Digitare “perfmon” da “Esegui”. Se appare la seguente scheramata:
--------------------------Performance Monitor Control
--------------------------Unable to add these counters:
\Memory\Available MBytes
\Memory\% Committed Bytes In Use
\Memory\Cache Faults/sec
\Memory\Cache Faults/sec
\PhysicalDisk(*)\% Idle Time
\PhysicalDisk(*)\Avg. Disk Queue Length
\Network Interface(*)\Bytes Total/sec
--------------------------OK
---------------------------
bisogna ripristinare i performance counters. Per farlo, copiare il file:
c:\windows\system32\PerfStringBackup.ini
da una macchina con i performance counters funzionanti. Dopodichè digitare da riga di
comando:
lodctr /R:PerfStringBackup.INI
per ricaricarli.
98
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Appendice B
Configurazione della comunicazione tramite Remote Shell
Remote Shell (RSH) è una piccola applicazione linux in grado di eseguire oeprazioni a
riga di comando come altro utente e/o su un altro computer collegato in rete.
E‟ necessario ovviamente che il relativo pacchetto (rhs-client) sia installato sul computer
“client” dal quale ci si intende connettere, e soprattutto un‟appropriata configurazione del
computer “server” destinatario della connessione, in modo da garantire che su di esso sia
in esecuzione il demone rshd e che siano concessi i permessi al computer client:
-
Installare il pacchetto rsh-server
-
Configurare il file “/etc/securetty”, aggiungendo le seguenti righe di codice:
rsh
rlogin
rexec
chkconfig rsh on
chkconfig rlogin on
chkconfig xinetd on
rcxinetd stop
rcxinetd start
-
Aprire un‟eccezione nel firewall (qualora fosse abilitato)
Configurare il file “/etc/hosts.equiv” per consentire l‟accesso dell‟utente x dalla
macchina y. Ad esempio, inserendo la riga seguente, viene concesso il permesso
99
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
all‟utente “Utente” proveniente dalla macchina con IP 10.0.0.10
10.0.0.10
Utente
Qualora si voglia eseguire comandi in remoto come utente supervisor (ad esempio
“root”), è necessaria un‟ulteriore operazione di configurazione:
Va creata (se non esistente) nella root principale una cartella col nome dell‟utente,
contentente un hidden file “.rhosts”, nel quale vanno specificati indirizzi IP e nome utenti
ai quali si vuole concedere diritti di supervisor.
Ad esempio, nel caso di studio presentato nel capitolo4, la macchina con indirizzo
10.0.0.10 aveva necessità di connettersi alla macchina logbus per eseguire, come root,
operazioni a riga di comando, quindi nel file “.rhosts” era presente la seguente riga:
10.0.0.10
root
Per comunicazioni su reti considerate poco sicure, si preferisce usare la più sicura, ma
meno performante, Secure Shell (SSH), la cui configurazione peraltro è analoga a quella di
RSH, nonchè facilitata dalle interfacce dei moderni sistemi operativi.
100
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Appendice C
Testbed Manager della campagna di test
Si riporta qui di seguito lo script completo del testbed manager utilizzato nella campagna
di test relativa al caso di studio analizzato nel Capitolo 4:
____
#!/bin/bash
BINDIR=/home/carlo/d4lCampaign/apache_ws/bin
LOGDIR=/home/carlo/d4lCampaign/apache_ws/logs
FAULTYDIR=/home/carlo/d4lCampaign/apache_ws_faulty
SAVEDIR=/home/carlo/d4lCampaign/save
MOUNT=/
PROGDIR=`pwd`
cd $PROGDIR
#Operazioni preventive: [optional]:
# ./kill_logBus.sh
# ./kill_apache_all.sh
# ./on_logBus.sh
# Backup del webserver:
cp $BINDIR/httpd httpd.orig
# Abilitazione dei core dump:
echo "Turning on core dumps"
sudo bash -c "echo `pwd`'/core' | sudo cat > /proc/sys/kernel/core_pattern"
ulimit -c 20000
trap "echo child signalled me" 15
# Aggiornamento lista test:
ls $FAULTYDIR > test_list.txt
TOT_TESTS=`wc -l test_list.txt|awk '{print $1}'`
# Scorrimento lista test:
for TEST in `seq 1 $TOT_TESTS`
do
BINARY=`awk 'NR=='$TEST' {print $0}' test_list.txt`
101
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
FAULT=`perl -e '$_="'$BINARY'";s/httpd_//;print;'`
# Backdoor for pausing tests
if [ -e freeze.txt ]
then
sleep 1000000000
fi
# Stop if there is no available space
FREE_SPACE_KB=`df|awk '$6=="'$MOUNT'" {print $4}'`
if [ $FREE_SPACE_KB -lt 10000 ]
then
echo "Low free disk space on $MOUNT !"
sleep 1000000000
fi
echo "Running test: $FAULT"
#continue
if [ ! -e $FAULTYDIR/httpd_$FAULT ]
then
echo "Skipping fault: $FAULT"
continue
fi
if [ -e $SAVEDIR/$FAULT ]
then
echo "Test already done: $FAULT"
continue
fi
# Istallazione Faulty System
echo "Installing Faulty Web Server"
rm $BINDIR/httpd
cp $FAULTYDIR/httpd_$FAULT $BINDIR/httpd
if [ $? -ne 0 ]
then
while [ true ]
do
# Try again
echo "Retrying copy"
ps axu|grep "httpd" |grep -v grep|awk '{print $2}'|xargs kill -s SIGKILL
ps axu|grep "apachectl" |grep -v grep|awk '{print $2}'|xargs kill -s SIGKILL
cp $FAULTYDIR/httpd_$FAULT $BINDIR/httpd
# cp $FAULTYDIR/httpd_$FAULT $BINDIR/.libs/lt-httpd
if [ $? -eq 0 ]
then
break
fi
done
fi
echo "Clearing logs"
echo > $LOGDIR/error_log
102
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
echo > $LOGDIR/access_log
rm $LOGDIR/httpd.pid
echo "Create temporary file in log directory"
touch $SAVEDIR/$FAULT
echo "Clearing semaphores"
# see http://atmail.com/kb/2007/apache-error-no-space-left-on-device/
ipcs -s | grep fdpfi | awk '{print "ipcrm sem " $2}' | sh
# Avvio Target System
echo "============= STARTING THE APACHE WS ============"
$BINDIR/apachectl start &
sleep 1
# Verifica se il sistema si è avviato
APACHECTL=`ps aux|grep "apachectl"|grep -v grep|wc -l`
HTTPD=`ps aux|grep "httpd"|grep -v grep|wc -l`
if [ $APACHECTL -ne 0 ]
then
echo "======== Problem with APACHE ctl, still running .... ========"
while [ $APACHECTL -ne 0 ] || [ $HTTPD -ne 0 ]
do
ps axu|grep "httpd" |grep -v grep|awk '{print $2}'|xargs kill -s SIGSEGV
ps axu|grep "apachectl" |grep -v grep|awk '{print $2}'|xargs kill -s SIGKILL
sleep 1
APACHECTL=`ps aux|grep "apachectl"|grep -v grep|wc -l`
HTTPD=`ps aux|grep "httpd"|grep -v grep|wc -l`
done
echo "HANG" > outcome.txt
echo "Web Server not started: hanged"
echo "Saving logs"
rm $SAVEDIR/$FAULT
mkdir -p $SAVEDIR/$FAULT
echo "NO_START" >> outcome.txt
mv $LOGDIR/* $SAVEDIR/$FAULT
mv workload.txt $SAVEDIR/$FAULT
#
mv core* $SAVEDIR/$FAULT
rm core*
mv outcome.txt $SAVEDIR/$FAULT
sleep 6
# Save FFDA logs
./send_socket_msg 10.0.0.5 4999 $FAULT &
# Kill Logbus-ng, Kill Target System. Restart Logbus-ng, Restart FFDA Monitor
./kill_logBus.sh
./kill_apache_all.sh
./on_logBus.sh
./send_socket_msg 10.0.0.5 4999 "RESTART"
103
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
sleep 2
continue
fi
echo "======> https -> $HTTPD value ========="
if [ $HTTPD -eq 0 ]
then
echo "======= WebServer not started, HELP!!!=============="
if [ `ls core*|wc -l` -ne 0 ]
then
echo "Web Server not started: crash"
echo "CRASH" > outcome.txt
else
echo "Web Server not started: error"
echo "VALUE" > outcome.txt
fi
# Save Apache logs
echo "Saving logs"
rm $SAVEDIR/$FAULT
mkdir -p $SAVEDIR/$FAULT
echo "NO_START" >> outcome.txt
mv $LOGDIR/* $SAVEDIR/$FAULT
mv workload.txt $SAVEDIR/$FAULT
#
mv core* $SAVEDIR/$FAULT
rm core*
mv outcome.txt $SAVEDIR/$FAULT
sleep 6
# Save FFDA logs
./send_socket_msg 10.0.0.5 4999 $FAULT &
# Kill Logbus-ng, Kill Target System. Restart Logbus-ng, Restart FFDA Monitor
./kill_logBus.sh
./kill_apache_all.sh
./on_logBus.sh
./send_socket_msg 10.0.0.5 4999 "RESTART"
sleep 2
continue
fi
sleep 1
# Avvio del Workload
echo "================== RUNNING WORKLOAD ================"
./workload.sh > workload.txt 2>&1
sleep 12
echo "Test Report"
cat workload.txt
# ORACOLO : Esito del test
OUTCOME=
104
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
if [ `ls $PROGDIR/core.*|wc -l` -ne 0 ]
then
# CRASH
OUTCOME="CRASH"
else
NUM_TIMEOUTS=`perl -l -n -e 'BEGIN {$res=0} if(/client-timo\s(\d+).*socket-timo\s(\d+)/)
{$res=$1+$2} END {print $res}' workload.txt`
if [ $NUM_TIMEOUTS -gt 0 ]
then
# HANG
OUTCOME="HANG"
# Salvataggio del core dump
ps axu|grep "httpd" |grep -v grep|awk '{print $2}'|xargs kill -s SIGSEGV
else
NUM_ERRORS=`perl -l -n -e 'BEGIN {$res=0} if(/^Errors:\stotal\s(\d+)/) { $res=$1 }
END {print $res}' workload.txt`
if [ $NUM_ERRORS -gt 0 ]
then
# VALUE
OUTCOME="VALUE"
else
# NO FAILURE
OUTCOME="NO FAILURE"
fi
fi
fi
echo "Test outcome: "$OUTCOME
echo "$OUTCOME" > outcome.txt
#Save Apache Logs
echo "Saving logs"
rm $SAVEDIR/$FAULT
mkdir -p $SAVEDIR/$FAULT
mv $LOGDIR/* $SAVEDIR/$FAULT
mv workload.txt $SAVEDIR/$FAULT
rm core*
mv outcome.txt $SAVEDIR/$FAULT
# Save FFDA Logs
./send_socket_msg 10.0.0.5 4999 $FAULT
# Kill Logbus-ng, Kill Target System. Restart Logbus-ng, Restart FFDA Monitor ./kill_logBus.sh
./kill_apache_all.sh
./on_logBus.sh
sleep 2
./send_socket_msg 10.0.0.5 4999 "RESTART"
sleep 2
echo
echo "---------------------------------------------------------------"
echo
done
105
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
Bibliografia
[1]
C. Laprie. "Dependable Computing and Fault Tolerance: Concepts and
terminology," in Proc. 15th IEEE Int. Symp. on Fault-Tolerant Computing, 1985
[2]
Ravishankar
K.
Iyer,
Zbigniew
Kalbarczyk,
Mahesh
Kalyanakrishnan.
“Measurement-Based Analysis of Networked system vailability”
[3]
Lonvick, Chris. "The Syslog BSD Protocol". IETF. RFC 3164.
[4]
Gerhards,
Rainer.
"The
Syslog
Protocol".
IETF.
RFC
5424.
http://tools.ietf.org/html/rfc5424
[5]
M. Cinque, R. Natella, A. Pecchia, S. Russo. "Improving FFDA of Web Servers
trough a Rule-Based logging approach". 2008
[6]
M. Cinque, D. Cotroneo, A. Pecchia. “Evaluation of Complex Systems. A Logging
Approach for Effective Dependability”. 2009
[7]
M. Cinque, D. Cotroneo, A. Pecchia. “Enabling Effective Dependability
Evaluation of Complex Systems via a Rule-Based Logging Framework”. 2009
[8]
M. Cinque, D. Cotroneo, A. Pecchia. “Towards a Framework for Field Data
Production and Management”. 2008
[9]
A.Anzivino. “Logbus-ng: a software logging bus for Field Failure Data Analysis in
distributed systems”. 2010
106
Realizzazione di un framework per la valutazione dei meccanismi di logging di sistemi
software
[10] V.Alfieri. “Realizzazione di una API di logging per la Field Failure Data Analysis
in ambienti distribuiti”. 2010
[11] Laboratorio per i sistemi mobili MOBILAB, University of Naples “Federico II”.
“Logbus-ng core version 2.0 Documentation”. 2010
[12] R. Chillarege. “Orthogonal Defect Classification”. 1995
[13] J.A. Durães and H.S.Madeira. “Emulation of Software faults: A Field Data Study
and a Practical Approach”. 2006.
[14] D. Cotroneo, R. Natella, A. Pecchia, S. Russo “An Approach for Assessing Logs
by Software Fault Injection”. 2009
[15] http://www.mobilab.unina.it/SFI.htm [online]
[16] Apache Foundation. “Apache Web Server”. http://www.apache.org. [online].
[17] GCC. "The Gcov tool". http://gcc.gnu.org/onlinedocs/gcc/Gcov.html. [online]
[18] GCC. “The GNU Compiler Collection". http://gcc.gnu.org/ [online]
[19] HP. “Httperf”. http://www.hpl.hp.com/research/linux/httperf/ [online]
[20] OpenSUSE. http://www.opensuse.org [online]
107