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