Università degli Studi di Salerno Facoltà di Scienze Matematiche Fisiche e Naturali Dipartimento di Informatica Laboratorio di Sistemi Operativi II FASTA MapReduce: analisi di sequenze genomiche e proteomiche utilizzando Hadoop 2 Professore Prof. Giuseppe Cattaneo Dott. Gianluca Roscigno Studenti Francesco Farina Marco Amoruso Anno Accademico 2013-2014 Abstract In questo documento, è presentata un’applicazione il cui scopo è allineare sequenze genomiche e proteomiche avvalendosi di algoritmi di Pairwise alignment. Tale software, realizzato per sfruttare il framework Apache Hadoop [2] si basa su FASTA [1]. L’allineamento di sequenze, rappresentate come una successione di caratteri, è elaborato grazie alla potenza computazionale di una griglia in maniera da poter confrontare un vasto numero di genomi con uno di riferimento. I Indice 1 Introduzione 1.1 Obiettivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 2 Analisi preliminare 2.1 Pairwise alignment . . . . . . . . 2.2 Smith-Waterman . . . . . . . . . 2.3 Algoritmi euristici . . . . . . . . . 2.3.1 FASTA . . . . . . . . . . . 2.3.1.1 Algoritmo . . . . 2.3.1.2 Formato FASTA . . . . . . 3 3 4 5 6 6 8 . . . . . . 9 9 9 10 11 11 12 . . . . . . 13 13 14 16 17 18 20 . . . . . . . 21 21 22 23 26 26 28 31 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 FASTA per Hadoop 3.1 Soluzioni proposte . . . . . . . . . . . . . . 3.1.1 Porting di FASTA in Java . . . . . . 3.1.2 Implementazione di JFASTA . . . . . 3.2 Soluzione adottata . . . . . . . . . . . . . . 3.2.1 Pro e contro della soluzione adottata 3.2.2 FASTA Benchmark . . . . . . . . . 4 Implementazione Map-Reduce 4.1 Overview . . . . . . . . . . . . 4.2 Dettagli implementativi . . . 4.2.1 Inizializzazione . . . . 4.2.2 Fase di Map . . . . . . 4.2.3 Fase di Reduce . . . . 4.2.4 Risultato finale . . . . 5 Tests e Benchmarking 5.1 Configurazione di test . . . . 5.2 Il tool utilizzato per le analisi 5.3 Benchmark . . . . . . . . . . 5.3.1 Tempi di esecuzione . . 5.3.2 CPU . . . . . . . . . . 5.3.3 RAM . . . . . . . . . . 5.3.4 Disco . . . . . . . . . . . . . . . . . . . . . . . II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . INDICE III 5.3.5 5.3.6 5.3.7 5.3.4.1 Lettura . . . . . . . . 5.3.4.2 Scrittura . . . . . . . Pacchetti di Rete e Throughput 5.3.5.1 IN . . . . . . . . . . . 5.3.5.2 OUT . . . . . . . . . . Anomalia riscontrata . . . . . . Analisi Prestazione . . . . . . . 5.3.7.1 Speedup . . . . . . . . 5.3.7.2 Efficienza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 32 33 34 36 38 39 39 40 6 Conclusioni 42 Bibliografia 43 A Appendice 44 A.1 Link al codice sorgente . . . . . . . . . . . . . . . . . . . . . . . . . 44 Capitolo 1 Introduzione In questo documento si presenta l’utilizzo di Apache Hadoop applicato al campo della bioinformatica. In particolare, viene affrontato il problema del pairwise alignment di sequenze di DNA o proteine mediante algoritmi ad hoc, i quali necessitano di enorme potenza di calcolo e tempi di esecuzione molto lunghi. Il problema dell’allineamento di sequenze di DNA e di proteine deriva dalla necessità di confrontare e misurare la similarità di due o più sequenze, determinando un allineamento ottimale fra tutti i numerosi possibili allineamenti. In generale, essendo la natura conservativa, nel caso in cui una sequenza risulti essere somigliante a quella di un nucleotide o di una proteina, di cui è noto il comportamento, allora si è in grado di attribuire, alla sequenza in questione, una funzione identica oppure simile. Numerose sono le motivazioni per il confronto di tali sequenze [3], ad esempio: • determinare caratteristiche fisiche e genetiche a partire da sonde di rilevamento; • trovare nuovi elementi informativi in proteine e sequenze di DNA; • attribuire un ruolo ad un frammento clonato di DNA in un sistema, comparandolo con segmenti contenuti in banche di dati; • identificare l’identità di un assassino, attraverso il confronto del DNA con quello dei possibili sospetti. Per quanto riguarda lavori di ricerca e non solo, il problema dell’allineamento di sequenze può rappresentare la consuetudine. 1 Capitolo 1: Introduzione 2 Questo tipo di analisi, da un punto di vista prettamente informatico, risulta essere estremamente oneroso ed incide fortemente sui tempi necessari per ottenere i risultati richiesti, con conseguente impennate dei costi relativi all’intero processo. 1.1 Obiettivi Lo scopo di questo progetto è quello di velocizzare il processo di analisi di sequenze di genomi, mediante l’uso del paradigma Map-Reduce. Tale problema sarà analizzato in base ai vari approcci ed algoritmi che lo risolvono, al fine di valutarne la parallelizzabilità, in modo tale da poter utilizzare al meglio il cluster Hadoop a disposizione, composto da commodity hardware. Infine, saranno confrontate la soluzione già esistente con quella proposta in questo progetto, al fine di valutare il grado di bontà della soluzione stessa e la percentuale di speed-up che essa apporta. Capitolo 2 Analisi preliminare In questo capitolo si illustrano alcuni algoritmi, atti alla risoluzione delle problematiche accennate nel capitolo precedente, considerati per il calcolo del pairwise alignment, mediante Apache Hadoop. 2.1 Pairwise alignment Innanzitutto, per pairwise sequence alignment si intende il processo di allineamento di due sequenze al fine di ottenere i massimi livelli di identità, per poter stabilire un determinato grado di similarità. L’allineamento di sequenze molto brevi è semplice e può essere fatto da un essere umano. Tuttavia la maggior parte dei problemi interessanti richiedono l’allineamento di sequenze lunghe, che non possono essere allineate unicamente dall’uomo. Infatti, l’allineamento ottimale di due sequenze entrambe di lunghezza n è uno fra tutti i diversi possibili allinea1 2 menti, ovvero 2n che è approssimativamente pari a 2n . Quindi la conoscenza n umana è applicata nella costruzione di algoritmi in grado di produrre allineamenti di sequenze di alta qualità. In generale, gli approcci per l’allineamento di sequenze dal punto di vista computazionale si dividono in due categorie: globale e locale. Diversi algoritmi si basano su tali approcci ed utilizzano un sistema di scoring, che assegna dei punteggi necessari per il calcolo dell’allineamento di due sequenze. Tali algoritmi includono lenti ma corretti metodi, come di programmazione dinamica, ed efficienti algoritmi euristici o probabilistici che non garantiscono un risultato ottimo. Di seguito vengono presentati alcuni algoritmi e sistemi considerati per il calcolo dell’allineamento di sequenze, mediante l’utilizzo di Apache Hadoop. 3 Capitolo 2: Analisi preliminare 4 Più in dettaglio, vengono introdotti: • Smith-Waterman, algoritmo di programmazione dinamica; • BLAST e FASTA, algoritmi e strumenti basati su metodi euristici. 2.2 Smith-Waterman L’algoritmo di Smith-Waterman [4], proposto da Temple F. Smith e Michael S. Waterman nel 1981, sfrutta un approccio locale per l’allineamento di sequenze. In questo modo, piuttosto che considerare le sequenze nella loro interezza, l’algoritmo confronta segmenti di tutte le possibili lunghezze ed è in grado di trovare l’allineamento ottimale, rispetto al sistema di scoring utilizzato: • matrice di sostituzione, contenente gli score associati ad ogni coppia di caratteri presenti nelle sequenze, in cui per il confronto di due caratteri a e b, s(a, b) indica lo score ad esso associato; • schema di gap-scoring, che introduce un gap penality per ridurre lo score, ogni qualvolta vengono inseriti gap. L’algoritmo di Smith-Waterman, date due sequenze x ed y di lunghezza n ed m, costruisce una matrice F di dimensione n ú m, dove F (i, j), con i=1..n ed j=1..m, indica lo score locale della sottosequenza corrente. Inizialmente l’algoritmo pone F (0, 0) a 0 e successivamente procede a riempire ricorsivamente F (i, j) dall’angolo in alto a sinistra verso quello in basso a destra, con il massimo fra i seguenti valori: 1. F (i, j) = 0, corrisponde a considerare un nuovo allineamento; 2. F (i, j) = F (i ≠ 1, j ≠ 1) + s(xi , yj ), caso in cui xi , yj possono essere allineate; 3. F (i, j) = F (i ≠ 1, j) – gap penalty, caso in cui xi è allineata ad un gap; 4. F (i, j) = F (i, j ≠ 1) – gap penalty, caso in cui yj è allineata ad un gap. Per ogni F (i, j), l’algoritmo tiene traccia della cella da cui si è derivato il suo valore. Una volta riempita la matrice F, a partire dal valore F (i, j) contenente Capitolo 2: Analisi preliminare 5 lo score massimo, l’algoritmo esegue traceback, ovvero costruisce l’allineamento a partire da tale cella e seguendo i riferimenti alle celle, i quali hanno portato a tale cella. Ad ogni passo il processo di traceback si muove dalla cella corrente (i, j) verso una fra (i ≠ 1, j ≠ 1), (i ≠ 1, j) o (i, j ≠ 1), aggiungendo i simboli associati alle celle all’allineamento finale, fino al raggiungimento di una cella contenente il valore 0, il quale rappresenta l’inizio dell’allineamento. La complessità di spazio dell’algoritmo è pari a O(m ú n), in quanto costruisce e riempe una matrice di dimensioni n ú m, e la stessa complessità in termini di tempo, dovuta al processo di riempimento della matrice con tutti gli score, F (i, j). Questo equivale a dire che, per poter confrontare due sequenze, che occupano entrambe 5MB, e calcolarne l’allineamento ottimo, sarebbe necessario uno spazio in memoria pari al prodotto fra il valore in byte delle sequenze con la rappresentazione in byte di un intero, ovvero circa: 5000000 ú 5000000 ú 4 byte = 100TB. Quindi risulta impraticabile utilizzando commodity hardware, poter memorizzare la matrice sia sul disco che in RAM sulla macchina. Inoltre, non è possibile suddividere la matrice in blocchi ed analizzare ogni blocco singolarmente, in quanto il calcolo dello score di F (i, j) coinvolge anche i valori F (i≠1, j ≠1), F (i≠1, j) e F (i, j ≠ 1), che potrebbero appartenere ad altri blocchi; in tale situazione sarebbe necessario mantenersi in memoria o sul disco tutti i blocchi, ritornando così al problema di partenza. Per cui, per poter confrontare tali sequenze bisogna cambiare approccio, utilizzare un algoritmo euristico. 2.3 Algoritmi euristici Un altro approccio per il calcolo dell’allineamento di due sequenze è basato su k-tuple o word. Tale approccio si basa su algoritmi euristici che non garantiscono come risultato un allineamento ottimo, ma sono algoritmi molto più efficienti rispetto a quelli di programmazione dinamica. Questi metodi, in generale, identificano una serie di brevi e non sovrapposte sottosequenze (word) a partire da una sequenza, le quali vengono poi confrontate con altre parole candidate dell’altra sequenza. Le relative posizioni di queste word nelle due sequenze vengono sottratte per ottenere un offset, il quale indicherà una regione di allineamento, nel caso in cui più parole distinte producono lo stesso offset. Solamente se queste regioni vengono rilevate, viene applicato un criterio di allineamento più accurato; ciò elimina Capitolo 2: Analisi preliminare 6 la necessità di confrontare sottosequenze che non appaiono simili. BLAST e FASTA sono i tool di ricerca, basati su database, più conosciuti che utilizzano tale approccio. Entrambi i sistemi utilizzano un’approssimazione dell’algoritmo di Smith-Waterman e si basano sulla definizione di un determinato k, che indica la lunghezza delle sottosequenze o parole. La differenza sostanziale fra i due è che BLAST risulta essere più ottimizzato, in quanto analizza solamente le parole che hanno un match più significativo, a differenza di FASTA. Non essendo disponibile codice sorgente in Java, la scelta dell’algoritmo sul quale basarsi e su cui costruire l’implementazione è ricaduta sull’algoritmo utilizzato da FASTA, in quanto risulta essere una strada praticabile nel tempo a disposizione, rispetto all’implementazione dell’algoritmo di BLAST, il quale utilizza metodi complessi di matematica e statistica. 2.3.1 FASTA L’algoritmo di FASTA venne progettato nel 1985 da Lipman e Pearson. A partire da due sequenze, denominate come query sequence e database sequence di lunghezza rispettivamente n ed m, FASTA approssima l’allineamento ottimale cercando e riscontrando le k-tuple (match). L’algoritmo assume che sequenze relate avranno regioni somiglianti, e cercando mediante k-tuple, FASTA è in grado di trovare rapidamente piccole regioni identiche localmente. 2.3.1.1 Algoritmo L’algoritmo di FASTA [6] [7] è composto da diverse fasi: 1. FASTA crea una hash table di tutte le possibili k-tuple, attraversa l’intera query sequence e pone nella tabella le posizioni di tutte le possibili k-tuple. Ogni k-tupla nella database sequence viene ricercata nella hash table ed, ad ogni match l’algoritmo contrassegna le celle in cui questo si è verificato. Quindi l’algoritmo nella prima fase determina tutti i match di lunghezza k fra le due sequenze, chiamati hot-spots. Un hot-spot è dato dalla coppia (i, j), dove i e j sono le posizioni iniziali di un match di lunghezza k. Ogni hot-spot (i, j) giace sulla diagonale (i ≠ j) della matrice, che si avrebbe nel caso di programmazione dinamica. Utilizzando tale schema, la diagonale Capitolo 2: Analisi preliminare 7 principale ha come identificativo 0 (i = j), mentre le diagonali al di sopra della principale possiedono un identificativo positivo (i>j) e quelle al di sotto negativo (i<j). Una diagonal run è un insieme di hot-spot, che si trovano in una sequenza consecutiva sulla stessa diagonale ed ad ognuna di esse è assegnato uno score. 2. L’algoritmo ricava le dieci diagonal run con lo score maggiore, identificando ogni punto della matrice marcato, ed aggiungendo uno score positivo per ogni altra cella contrassegnata sulla diagonale, sottraendo invece una penalità per ogni cella non contrassegnata. Questi dieci migliori segmenti vengono conservati, mentre tutti i restanti vengono scartati. 3. A questo punto viene assegnato nuovamente uno score ad ognuna delle dieci diagonali, mediante una matrice di sostituzione (PAM o BLOSUM ), ed ogni diagonale con uno score inferiore ad una determinata soglia viene scartata. La diagonale con il migliore score viene denominata come init1. 4. L’algoritmo calcola gli score dell’unione di ogni possibile combinazione di diagonali adiacenti. Per calcolare lo score di una serie di unioni di diagonali, gli score di ogni diagonale vengono sommati, ed una costante di penalità viene sottratta ogni qualvolta due sottosequenze vengono unite con un gap. Tutti gli allineamenti con uno score al di sotto di una determinata soglia vengono scartati. 5. L’algoritmo definisce una diagonale avente una determinata larghezza, costruita attorno alla diagonale init1. FASTA assume che l’allineamento ottimo includerà o sarà vicino alla diagonale init1. 6. Infine, viene applicato Smith-Waterman su tale diagonale per trovare l’allineamento finale delle due sequenze. Sebbene l’algoritmo di FASTA sia molto più veloce degli algoritmi di programmazione dinamica, non garantisce come risultato l’allineamento ottimo fra due sequenze. Poiché usa le k-tuple per accelerare i calcoli, l’algoritmo può non considerare piccole aree di similarità e quindi vi è la possibilità di un disallineamento fra le due sequenze. Inoltre, limitando la larghezza dell’area di lavoro dell’algoritmo di programmazione dinamica, l’algoritmo di FASTA può produrre un allineamento non ottimale. Questo è chiaramente un trade-off fra velocità ed accuratezza. Capitolo 2: Analisi preliminare 2.3.1.2 8 Formato FASTA Il tool FASTA ha originato un formato standard per la rappresentazione standard nel campo della bioinformatica [8]. In tale formato testuale, una sequenza inizia con una descrizione sulla prima linea del file, ed a seguire le linee che rappresentano i dati della sequenza. La descrizione viene disambiguata attraverso il simbolo > all’inizio della prima riga. Nella figura in basso viene mostrata una sequenza in formato FASTA. Figura 2.1 Capitolo 3 FASTA per Hadoop L’implementazione dell’algoritmo FASTA per Hadoop si è evoluta attraverso più fasi, alcune delle quali, pur essendosi rivelate fallimentari, sono comunque servite a produrre un’implementazione corretta ed efficace, nonostante i trade-off a cui ci si è dovuti adattare. 3.1 3.1.1 Soluzioni proposte Porting di FASTA in Java Il primo approccio per eseguire l’algoritmo FASTA sul framework Hadoop è stato un tentativo di porting dell’algoritmo stesso dal linguaggio C, in cui è originariamente implementato, a Java. Essendo il codice sorgente disponibile [5], si è partiti con una analisi statica, in modo da poter individuare le componenti chiave, per poi rappresentarle nella versione Java. Attraverso tale analisi, sono sorte diverse problematiche relative: • scarsa presenza di commenti all’interno del sorgente, rendendo così difficile la comprensione della semantica del codice; • un elevato numero di file (96), così come la dimensione media dei file (migliaia di loc), causa un estremamente oneroso lavoro di porting dell’applicazione. • la natura del codice, intrinsecamente parallela ed ottimizzata, complica l’estrapolazione delle funzionalità. 9 Capitolo 3: FASTA per Hadoop 10 Tali problematiche hanno portato a cambiare approccio implementativo, ovvero utilizzare il codice sorgente di FASTA, attraverso la tecnologia JNI. Ma anche tale soluzione è stata scartata, a causa della natura del codice sorgente, ovvero un programma eseguibile. Infatti, JNI si basa principalmente sul richiamo di librerie e non di programmi eseguibili. A questo punto, scartate le ipotesi discusse in precedenza, si è scelto di implementare l’algoritmo, attraverso le linee fornite dallo pseudo-codice 2.3.1.1. 3.1.2 Implementazione di JFASTA La realizzazione dell’algoritmo in Java è iniziata senza una base di partenza, in termini di codice, ed è proseguita solamente seguendo i passi forniti dallo pseudocodice. In tale processo, si è posta particolare attenzione verso l’utilizzo delle risorse, in modo da ottimizzare il codice e soprattutto alla deallocazione delle risorse non più utili, per essere in grado di prevenire sprechi di memoria, considerando la già elevata complessità in termini di spazio dell’algoritmo. Al termine dell’implementazione, si è testato il risultato, JFASTA su diverse macchine aventi cpu Intel I7 quad-core con Hyperthreading, operante alla frequenza di 2.8 Ghz e 8 GB di RAM DDR3 a 1333MH. I tempi di esecuzione dell’algoritmo su input di sequenze di DNA pari a 500 KB sono stati di 59 sec circa, con un utilizzo della memoria, però, nei momenti di picco massimo, pari a 1.2GB circa. Lo stesso test è stato ripetuto poi su diverse macchine appartenenti al cluster Hadoop messo a disposizione per il progetto, dotate di cpu Celeron dual-core con frequenza di 2,4GHz con 4GB di memoria RAM DDR2 667MHz. Il test reale è avvenuto, però, all’interno delle macchine virtuali installate sui suddetti computer, alle quali sono allocati soltanto 3GB di RAM. L’esecuzione dell’implementazione di JFASTA in tale ambiente purtroppo non ha dato risultati. Questo è dovuto, secondo varie analisi, a due fattori: • le scarse risorse a disposizione delle macchine, che come è noto appartengono ad un cluster con commodity hardware; • l’implementazione di JFASTA essendo strettamente sequenziale, risulta essere poco efficiente in confronto all’implementazione originale dell’algoritmo, che fa uso di istruzioni SSE ed un massiccio utilizzo di parallelizzazione di basso livello. Capitolo 3: FASTA per Hadoop 11 L’implementazione di JFASTA, è comunque reperibile all’indirizzo https://github. com/indiependente/jfasta.git. A seguito di tali considerazioni, si è scelto di scartare anche questa soluzione, in quanto inutilizzabile ai fini del progetto. 3.2 Soluzione adottata Dopo le difficoltà di creare un’implementazione dell’algoritmo in questione, la soluzione adottata, a fronte dei diversi tentativi di realizzare una versione Java dell’algoritmo di FASTA, è stata frutto di diverse analisi che hanno portato alla scelta di utilizzare l’implementazione originale. Data la necessità di utilizzare in ambiente Hadoop un programma scritto in Java e vista la scelta di utilizzare l’implementazione di FASTA in C, si è deciso di implementare un semplice wrapper in Java che, mediante la classe ProcessBuilder, permettesse di richiamare e lanciare un file eseguibile. 3.2.1 Pro e contro della soluzione adottata La scelta di utilizzare l’implementazione originale di FASTA, attraverso un wrapper Java, ha portato ad alcuni trade-off, i quali vengono elencati ed analizzati di seguito: • Vantaggi – l’utilizzo di una componente off-the-shelf, efficiente ed efficace, libera risorse utilizzabili per altri task del progetto. – l’implementazione estremamente efficace, realizzata mediante istruzioni SSE e tecniche di parallelismo a basso livello, permette a FASTA di eseguire task in maniera molto più rapida. – le euristiche utilizzate nell’algoritmo permettono, come si vedrà nel paragrafo successivo, un uso della memoria estremamente ottimizzato. • Svantaggi – l’invocazione di un file eseguibile dall’interno di un programma e la sua esecuzione come black-box sicuramente non fa parte delle best pratices della programmazione, in quanto non è possibile, in alcun modo, controllare l’esecuzione, le situazioni di errore o fare debugging. Capitolo 3: FASTA per Hadoop 12 A partire dalle considerazioni appena discusse si è scelto di utilizzare, quindi, l’implementazione in C di FASTA come fondamenta per la risoluzione del problema del pairwise alignment su Hadoop. 3.2.2 FASTA Benchmark Al fine di verificare la bontà dell’implementazione di FASTA, avendo un limitato tempo a disposizione è stato effettuato un test, di tipo sequenziale, su un input di 32 file, ognuno di circa 70 KB. Tale test, effettuato su una macchina appartenente al cluster Hadoop utilizzato in questo progetto, sarà utilizzato come unità di riferimento nei capitoli successivi, al fine di poter misurare i possibili miglioramenti derivanti da un’implementazione dello stesso utilizzando il paradigma Map-Reduce. L’esecuzione di FASTA sull’input descritto in precedenza ha impiegato 578,77 minuti. Il risultato sembra non essere esaltante, ma bisogna considerare che, dati 32 file in input, l’algoritmo computa su 32 ú 32 coppie. Più in dettaglio, ogni file di riferimento dell’input viene confrontato con il restante input, ed il confronto fra il file di riferimento con sé stesso viene scartato. Ogni coppia, per essere valutata dall’algoritmo, impiega in media 35 secondi. Il dato più rilevante, però, risulta essere la quantità di memoria utilizzata: se il processore, grazie alle ottimizzazioni di parallelizzazione in FASTA, lavora in maniera costante al 198%, la memoria utilizzata dal programma si è rivelata essere, nei momenti di picco massimo, di circa 300 MB. Tale valore, confrontato con la memoria occupata dall’implementazione di JFASTA di circa 1.2 GB, giustifica da sola la scelta di utilizzare come soluzione FASTA. Capitolo 4 Implementazione Map-Reduce In questo capitolo si presenta l’approccio utilizzato per il raggiungimento della soluzione, sfruttando il paradigma Map Reduce, la sua architettura, la relativa implementazione e le scelte che hanno portato ad ottenere tale soluzione. 4.1 Overview Il problema di processare tutte le possibili coppie, a partire da un insieme di genomi memorizzati in file che rispettano il formato FASTA, può essere visto come: scegliere un genoma di riferimento e processare tutte le coppie il cui primo elemento è il genoma scelto. Tale operazione è ripetuta per ogni file appartenente all’insieme di genomi fornito in input. Il processo di elaborazione appena enunciato, è l’esatta descrizione ad alto livello di quel che l’applicazione si occupa di portare a termine. Infatti, come è illustrato dalla figura 4.1, si può notare come per ogni genoma fornito in input, questo venga preprocessato in una fase di inizializzazione, durante la quale esso è messo a disposizione dei mappers. La fase di inizializzazione prevede il caricamento sull’HDFS del file sotto lo pseudonimo di TARGET, in quanto è il file a cui ogni mapper dovrà far riferimento per quel "turno". La fase di Map, prevede il confronto tra il file TARGET del turno in questione con il file del genoma assegnato al mapper nel modo spiegato in dettaglio successivamente. Il confronto è realizzato utilizzando un eseguibile esterno chiamato FASTA36, il quale implementa l’algoritmo FASTA. Terminato il confronto, si provvede ad effettuare l’upload dell’output sul file system distribuito. Una volta terminata la fase di Map, segue la fase di Reduce che consiste nell’aggregazione dei risultati ottenuti per il genoma TARGET corrente 13 Capitolo 4: Implementazione Map-Reduce 14 in un unico file situato sull’HDFS. L’applicazione invocabile da linea di comando prende in input il path di una directory contenente gli n genomi da processare. Figura 4.1: Elaborazione dei genomi in input 4.2 Dettagli implementativi Di seguito viene esposta la soluzione introdotta precedentemente. Il deliverable è un file jar eseguibile da linea di comando: tale eseguibile prende in input due parametri quali, la modalità di esecuzione e la cartella di input. L’utilizzo della classe ProgramDriver messa a disposizione tra le utility del framework Hadoop, consente di modificare il comportamento di una applicazione, in funzione di un parametro fornito dall’utente. L’applicazione è invocata se il primo parametro ricevuto in input è "-a". L’eseguibile FASTA36 è un processo cpu-intensive che conviene eseguire in una singola istanza per volta, in quanto la concorrenza nell’ottenimento della risorsa processore andrebbe solo a far decadere le performance. Proprio per questo motivo si è scelto di permettere l’esecuzione esclusiva di un singolo processo FASTA36. Capitolo 4: Implementazione Map-Reduce 15 Per ottenere tale modalità di esecuzione è stato necessario modificare la configurazione del Resource Manager Yarn, il quale si basa su container che effettuano la computazione chiamati Yarn Child, ed un unico container addetto all’orchestrazione dei servizi detto Application Master. I settings che meglio si sono adattati al caso dell’applicazione, sono mostrati dalla tabella 4.2. yarn-site.xml Proprietà Valore yarn.nodemanager.resource.memory-mb 2048 Descrizione Il quantitativo di memoria fisica, in MB, allocabile per i containers. mapred-site.xml Proprietà Valore Descrizione mapreduce.map.memory.mb 2048 Valore in MB relativo alla memoria allocabile per Mapper. mapreduce.reduce.memory.mb 2048 Valore in MB relativo alla memoria allocabile per Reducer. mapreduce.map.java.opts -Xmx1536M Parametro da passare alla JVM che gestisce il Mapper di un nodo relativo al limite di memoria che questa può utilizzare. mapreduce.reduce.java.opts -Xmx1536M Parametro da passare alla JVM che gestisce il Reducer di un nodo relativo al limite di memoria che questa può utilizzare. Per quanto riguarda invece la configurazione relativa all’HDFS, è mostrata nella tabella 4.2: Capitolo 4: Implementazione Map-Reduce 16 hdfs-site.xml Proprietà dfs.replication dfs.blocksize Valore Descrizione 3 Numero di repliche per blocco. 64m Taglia di un singolo blocco. Tale configurazione consente di avere su ogni nodo, un solo container e quindi un solo processo FASTA. Particolare fondamentale di questa applicazione è che essa si compone di tante iterazioni di processing quanti sono i file in input. Ciò si traduce in: • Prepare Input • ’genome œ GENOMES – Create and configure Job – Map Phase – Reduce Phase 4.2.1 Inizializzazione La fase di inizializzazione può essere suddivisa in due parti: • Preparazione dell’input • Configurazione ed esecuzione di un job per ogni file in input La preparazione dell’input consiste nella creazione di un unico file, contenente tante righe quanti sono i file in input. Ogni linea del file prodotto, è esattamente uno dei file presenti nella directory di input: tali file vengono portati in formato UNIX, ed ogni newline è convertito in un carattere delimitatore. Durante questa fase, inoltre per ogni file, si calcola la checksum MD5, mantenendo l’associazione nome file - checksum. L’hash è utilizzato per gestire in maniera non ambigua i file durante le fasi di Map e Reduce. Una volta preparato l’input, si procede con il main loop. Come illustrato in figura 4.2, per ogni genoma: Capitolo 4: Implementazione Map-Reduce 17 • si ottiene l’istanza di un job; • alla configurazione del job, viene aggiunto il nome del file TARGET e la sua checksum; • viene effettuata la copia dei file sull’HDFS; • il job viene configurato sulle giuste classi Mapper e Reducer; • gestione dell’input: come anticipato, il file TARGET deve essere confrontato con tutti gli altri file. Tale operazione di splitting è realizzata in maniera efficace grazie all’utilizzo del NLineInputFormat InputSplitter, il quale provvede a fornire in input ad ogni mapper una linea diversa del file originale. In questa maniera, avendo a disposizione un input che è multiplo del numero di nodi presenti nel cluster, si può ottenere una equa ripartizione del carico, generando così un numero di MapTask tale da disporsi equamente, in generale, sui nodi del cluster; • gestione dell’output: ogni mapper produce in output l’allineamento tra il genoma TARGET ed il genoma assegnatogli dallo splitter. Tale output è quel che il processo FASTA restituisce durante la sua esecuzione, in una quantità di testo variabile in base alla taglia dei genomi da confrontare. Si è scelto di redirigere questo output in un file, da caricare sull’HDFS in una cartella specifica per tale confronto, creata durante la fase di inizializzazione. • si procede con il lancio del job, utilizzando il metodo waitForCompletion: quest’ultima è una chiamata bloccante che restituisce il controllo al thread che lo invoca, al completamento del job; • al riottenimento del controllo, il file TARGET è eliminato dall’HDFS, in quanto il suo periodo di validità termina con l’iterazione che si sta concludendo. 4.2.2 Fase di Map La fase di Map, prevede un setup iniziale, in cui recupera il nome del file dalla configurazione, per poter copiare sul file system locale, nella directory di lavoro del mapper, il file TARGET del job in corso. Una volta ottenuto tale file, si converte in formato UNIX, e si memorizza la relativa checksum MD5. Il setup termina con l’acquisizione del path all’eseguibile FASTA36. Il Map vero e proprio è effettuato su un input del tipo <LongWritable, Text> dove Capitolo 4: Implementazione Map-Reduce 18 la chiave LongWritable rappresenta l’offset della linea dall’inizio del file, mentre il valore Text è la linea. Tale valore, contenente un intero genoma in formato FASTA è processato, per ottenere il file originale, in cui il delimitatore è sostituito da un newline. Un’ottimizzazione introdotta è quella di verificare che il file TARGET ed il file contenuto nel value Text, non siano in realtà lo stesso file. Per fare ciò, si ricorre al calcolo dell’hash MD5 del file estratto dal value: se tale checksum è identica a quella del TARGET, allora il processing dei due file può essere evitato ed il Map termina la sua esecuzione. Se invece, i due file sono diversi, si procede alla memorizzazione in locale del file ottenuto dal value, questo perché l’eseguibile FASTA prende in input i path a due file da confrontare. Infine, si procede alla configurazione degli argomenti da passare all’eseguibile. A questo punto è possibile invocare FASTA36 passando come argomenti i path al file TARGET ed al file da confrontare. Per notificare al framework Hadoop ed in particolare al Resource Manager Yarn, che l’esecuzione sta avvenendo correttamente, onde evitare la terminazione del MapTask, occorre aggiornare il contesto: ciò è realizzato mediante il metodo progress dell’oggetto Context, eseguito ogni mille linee di output prodotto dal processo FASTA36. Al termine dell’esecuzione del processo FASTA36, l’output prodotto, memorizzato in un file, viene salvato nel contesto utilizzando come chiave la checksum MD5 del file TARGET, restituendo così un output del tipo <Text, Text>. 4.2.3 Fase di Reduce La fase di Reduce si pone l’obiettivo di aggregare i risultati dei confronti prodotti dai singoli processi FASTA per un determinato file TARGET. Il Reducer ottiene in input la coppia < Text, Iterable<Text> >, cioè come chiave l’hash MD5 del file di riferimento, che ne garantisce l’unicità, e come valore la lista dei risultati ottenuti in seguito ad ogni confronto. Si prosegue con l’ottenimento della directory e la creazione del file di output sull’HDFS. Quindi, ogni elemento della lista di risultati viene concatenato al file di output sull’HDFS che al termine della fase, conterrà l’output di ogni confronto effettuato con il file TARGET. Infine, l’unico reducer restituisce un output costituito da una coppia di tipo <Text, Text>, in cui la chiave è il nome del file dei risultati aggregati, mentre il valore è il percorso al file appena creato sull’HDFS contenente l’insieme dei risultati. L’output viene scritto sul contesto del Reducer mediante l’utilizzo della classe MultipleOutputs, che consente inoltre di aggiungere la checksum del file TARGET. Capitolo 4: Implementazione Map-Reduce Figura 4.2: Dettaglio Schema MapReduce per singolo job 19 Capitolo 4: Implementazione Map-Reduce 4.2.4 20 Risultato finale Il risultato che si ottiene da un’esecuzione dell’applicazione è l’insieme degli allineamenti su ogni file in input, processati da FASTA per ognuno di questi ultimi. Tali allineamenti sono presentati in un formato molto esplicativo, il che semplifica la lettura all’utente. Per questo motivo, i file prodotti non necessitano di ulteriori elaborazioni. Capitolo 5 Tests e Benchmarking 5.1 Configurazione di test I tests sono avvenuti sulle macchine del laboratorio Reti all’interno del Dipartimento di Informatica dell’Università di Salerno. Sono state impiegate 34 macchine low-end così configurate: • Processore: Intel Celeron G530 Dual Core operante a 2.4Ghz, in grado di supportare le istruzioni Intel SSE di secondo livello. • Memoria Ram: 4096Mb DDR3 a 667Mhz. • Disco fisso: 500Gb operante a 5400rpm. • Scheda di rete ethernet Intel in grado di operare fino a 1Gbps. • Sistema operativo: Windows 7 Enterprise N a 64 bit. Queste macchine sono collegate tra di loro mediante uno switch Ethernet da 100Mbps. Su ciascuna di queste macchine è stata installata una macchina virtuale utilizzando la suite VMWare [9], così preparate: • VCore utilizzabili: 2. • Memoria Ram dedicata: 3072Mb. 21 Capitolo 5: Tests e Benchmarking 22 • Disco fisso: 120Gb. • Sistema operativo: Canonical Ubuntu 12.04 LTS a 64 bit su kernel GNU/Linux 3.8.x generic x86_64. La Java Virtual Machine utilizzata è la sequente: java version "1.7.0\_60" Java(TM) SE Runtime Environment (build 1.7.0\_60-b19) Java HotSpot(TM) 64-Bit Server VM (build 24.60-b09, mixed mode) In particolare su 33 di queste macchine virtuali è stato installato Apache Hadoop 2.2.0 compilato a 64 bit, in maniera tale da avere un master e 32 slaves. L’impiego delle macchine virtuali si è reso necessario perché non si disponeva dei privilegi di amministrazione sulle macchine fisiche e per avere un ambiente il più omogeneo e stabile possibile. La restante macchina è stata utilizzata per eseguire i test relativi al sequenziale, illustrati nella sezione 3.2.2. 5.2 Il tool utilizzato per le analisi Per poter monitorare le prestazioni del cluster durante l’esecuzione dei test è stato utilizzato il tool dstat [10]. Si tratta di un software in grado di visualizzare tutte le risorse di sistema (Cpu, memoria, disco, rete) in tempo reale fornendo chiaramente la grandezza e l’unità di misura dei dati in output. Più in dettaglio per la valutazione delle prestazioni del cluster abbiamo utilizzato il seguente comando: dstat -tcmgsdn –net-packets –float –noheaders –output out-dstat.csv 10 dove con le opzioni tcmgsdn si abilitano rispettivamente la visualizzazione dell’ora e della data per ogni riga dell’output, le statistiche sulla CPU, sulla memoria, sulla paginazione (page in e page out), lo swap, il disco (numero byte letti e scritti) e la rete (numeri pacchetti inviati e ricevuti, throughput dell’host in uplink e downlink). Nel precedente comando vengono utilizzate anche le seguenti opzioni: • net-packets: che mostra il numero di pacchetti ricevuti e trasmessi sulla rete. • float: che serve per forzare valori in output a float. Capitolo 5: Tests e Benchmarking 23 • noheaders: che disabilita la ripetizione dell’intestazione. • output: che permette la redirezione dell’output di dstat in un file csv. • 10: che indica il tempo di campionamento con cui vengono visualizzati i dati. 5.3 Benchmark In questa sezione, si analizzano i risultati ottenuti, dai test effettuati utilizzando l’applicazione descritta nel capitolo 4. Tali test sono stati effettuati, utilizzando un cluster composto da 8, 16 e 32 nodi. L’input sottomesso all’applicazione è il medesimo sottomesso all’applicazione sequenziale descritta nella sezione 3.2.2, ovvero 32 file contenenti genomi in formato FASTA, elencati in tabella 5.3. 1 La configurazione utilizzata per il cluster Hadoop, mostrata in tabella 4.2, prevede l’utilizzo di 31 YarnChild. Per cui uno dei 32 slave è utilizzato come Application Master, ottenendo così che il numero di macchine effettivamente allocate alla computazione del task sia 31, e non 32. La configurazione è analoga, per il cluster ad 8 e 16 nodi. I risultati ottenuti sono analizzati nelle sezioni a seguire, confrontando i grafici delle statistiche ad 8, 16 e 32 nodi, mettendo in mostra le differenze ed i singoli dettagli. I dati misurati comprendono statistiche riguardanti: • Utilizzo CPU • Utilizzo Memoria RAM • Lettura e Scrittura Disco • Pacchetti di rete inviati/ricevuti 1 • Throughput in input/output Sono stati selezionati tali file, per riuscire ad ottenere un risultato finale dall’esecuzione sequenziale, in tempo utile ai nostri scopi. Capitolo 5: Tests e Benchmarking 24 Capitolo 5: Tests e Benchmarking Nome file 25 Dimensione (KB) Bordetella-holmesii-F627-contig1.txt 69 Campylobacter-jejuni-subsp.-jejuni-NCTC-11168.txt 69 Ehrlichia-ruminantium-str.-Welgevonden-chromosome.fasta 69 Enterobacter-cloacae-subsp.-cloacae-GS1-GS1-c4.txt 69 GEN-Methanocaldococcus-jannaschii-DSM-2661-chromosome.txt 70 GEN-Methanothermobacter-thermautotrophicus-str-Delta-Hchromosome.txt 70 GEN-Streptococcus-pyogenes-NZ131.txt 70 Haemophilus-influenzae-PittEE.txt 69 Helicobacter pylori B38.fasta 69 Leptospira-licerasiae-serovar-Varillal-str.-VAR-0107180000002868.fasta 69 Marinomonas-sp.-MED121-scf-1099517007713.txt 69 Nautilia-profundicola-AmH.fasta 69 Neisseria-lactamica-Y92-1009.fasta 69 Photobacterium-angustum-S14-1099604003198.txt 69 Photobacterium-sp.-SKA34-scf-1099521381183.txt 69 Plesiomonas-shigelloides-302-73.txt 69 Prochlorococcus-marinus-str.-MIT-9211.fasta 69 Prochlorococcus-marinus-subsp.-marinus-str.-CCMP1375.fasta 69 Pseudomonas-aeruginosa BL20.fasta 69 Rickettsia-prowazekii-str.-NMRC-Madrid-E.txt 69 Rickettsia-prowazekii-str-Breinl.fasta 69 Salmonella-enterica-subsp-enterica-serovar-Enteritidis-str-78-1757SEEE1757-1.fasta 69 Salmonella-enterica-subsp-enterica-serovar-Enteritidis-str-CDC2010K-1543-SEEE1543-1.fasta 69 Salmonella-enterica-subsp-enterica-serovar-Enteritidis-str-CDC2010K-1884-SEEE1884-1.fasta 69 Sinorhizobium-meliloti-1021-plasmid-pSymA.fasta 69 Streptococcus-pyogenes-MGAS1882.fasta 69 Streptococcus-salivarius-M18.fasta 69 Streptococcus-agalactiae-ZQ0910.txt 69 Vibrio-alginolyticus-12G01-1100007009707.txt 69 Vibrio-angustum-S14-1099604003227.txt 69 Vibrio-parahaemolyticus-10329-VP10329-34.fasta 69 Weissella-koreensis-KACC-15510.fasta 69 Capitolo 5: Tests e Benchmarking 5.3.1 26 Tempi di esecuzione Tipo di esecuzione 5.3.2 Tempo (sec) Sequenziale 34726 8 Nodi 5486 16 Nodi 4631 32 Nodi 3327 CPU Figura 5.1 Il grafico mostra la precentuale di utilizzo di CPU, durante il test ad 8 nodi, su 32 job. Nella parte iniziale del grafico, lo scarso utilizzo di CPU, indica che sta avvenendo la fase di start del framework Hadoop, successivamente si presenta un picco, per ogni job in esecuzione. Dall’altezza di ogni cresta, si nota come l’utilizzo di CPU sia abbastanza intensivo, fino all’80% circa, caratteristica del processo FASTA, mentre l’ampiezza della singola cresta in questo grafico è la maggiore rispetto agli altri grafici riguardati la CPU, in quanto ogni slave ha da svolgere all’incirca quattro MapTask consecutivamente, ricoprendo quindi una durata di tempo maggiore. Per ogni cresta è possibile notare come, abbia un alto utilizzo di CPU iniziale per poi diminuire con il passare dei secondi, il che rispecchia la fase di Map cpuintensive, seguita dalla fase di Reduce. Capitolo 5: Tests e Benchmarking 27 Figura 5.2 Il grafico mostra la percentuale di utilizzo di CPU, durante un test a 16 nodi, su 32 job. La parte iniziale del grafico, rappresenta la fase di start del framework Hadoop, con il suo scarso utilizzo di CPU. Successivamente, si può riscontrare dalle creste presenti nell’immagine l’esecuzione dei job. Come nel grafico 5.1, si nota dall’altezza di ogni cresta, che il processo FASTA porta la CPU all’incirca all’80% di utilizzo, ma dall’ampiezza si osserva che la durata dell’elaborazione è inferiore. Questo avviene perché, ogni slave ha circa 2 MapTask da portare a termine. Anche in questo caso si nota come la fase di Map sia più intensiva rispetto a quella di Reduce, in ogni job. Figura 5.3 Capitolo 5: Tests e Benchmarking 28 Il grafico mostra la percentuale di utilizzo di CPU, durante un test a 32 nodi, su 32 job. La parte iniziale, rappresenta la fase di start del framework Hadoop, caratterizzata dallo scarso utilizzo di CPU. Successivamente, l’esecuzione dei job è riportata sotto forma di cresta nell’immagine. In questo caso, la CPU è sfruttata in maniera leggermente inferiore rispetto al grafico 5.2 e 5.1 e solamente in un caso supera il 75%, quindi in media, gli slaves lavorano leggermente meno, in quanto il carico è dilazionato su un maggior numero di macchine. Ad ogni slave è assegnato in generale un solo MapTask, terminando il job in tempo breve, come mostra l’ampiezza di ogni cresta. Ed è anche per questo motivo che la media di utilizzo di CPU risulta essere inferiore, in quanto il tempo di campionamento utilizzato per ottenere le statistiche si è rivelato essere leggermente elevato per la granularità dell’esperimento. 5.3.3 RAM Di seguito sono presentati i grafici relativi all’utilizzo di RAM durante un job, al variare del numero di slave. Figura 5.4 Capitolo 5: Tests e Benchmarking 29 Il grafico mostra la percentuale di utilizzo di memoria RAM, durante un test ad 8 nodi, su un singolo job. Come si nota, sono presenti quattro creste, ognuna rappresentante un MapTask, ciò è dovuto al fatto che avendo un numero di file in input pari a 32, ed avendo un numero di MapTask pari al numero di file, in generale ogni slave ha da elaborare in questo caso, circa quattro MapTask, vedasi la durata del job. La cresta iniziale, mostra come all’inizio del job, sia la macchina che svolge il ruolo di Application Master ad essere quella che necessita di più memoria RAM. Durante le esecuzioni dei task, gli slave utilizzano circa 700MB di RAM nelle fasi di Map, mentre 400MB durante le fasi di Reduce. Tale quantità di memoria coincide con quella mediamente utilizzata dal processo FASTA. L’immagine mostra come al termine delle fasi di Map, gli slaves rilascino memoria, mentre l’Application Master tenda ad avere una quantità di memoria utilizzata costante durante il monitoring dell’applicazione, tranne che al termine del job, in cui presenta un carico maggiore, dovuto alle operazioni da svolgere al completamento di quest’ultimo. Figura 5.5 Capitolo 5: Tests e Benchmarking 30 Il grafico mostra la percentuale di utilizzo di memoria RAM, durante un test a 16 nodi, su un singolo job. Sono visibili due creste, dovute a due MapTask assegnati agli slave, vedasi la durata del job. Anche in questo caso, così come nel grafico 5.4, all’inizio ed alla fine del job è l’Application Master ad avere la maggior quantità di RAM utilizzata, mentre durante le due fasi di Map, sono gli slave ad utilizzare circa 700MB di memoria. Figura 5.6 Il grafico mostra la percentuale di utilizzo di memoria RAM, durante un test a 32 nodi, su un singolo job. In questo caso, vi è un’unica cresta visibile, in quanto per questo esperimento ogni slave ottiene circa un MapTask. Come nei grafici 5.1 e 5.2, all’inizio ed al termine del job, è l’Application Master ad occupare più memoria RAM, mentre durante la fase di Map gli slave aumentano la quantità di memoria utilizzata, per poi rilasciarla al termine della fase. Capitolo 5: Tests e Benchmarking 5.3.4 31 Disco Di seguito sono presentati i grafici relativi all’utilizzo del disco durante un job, al variare del numero di slave. Da notare che i dati indicati sono misurati in KB/s, fattore che evidenzia la bassa quantità di dati in input. 5.3.4.1 Lettura Figura 5.7 Figura 5.8 Figura 5.9 Capitolo 5: Tests e Benchmarking 32 I grafici mostrati, presentano le operazioni di lettura necessarie durante l’esecuzione di un singolo job. Nella sezione iniziale dei grafici, si mostra l’avvio del framework Hadoop. Tale fase prevede la configurazione dei nodi del cluster, a partire da file che risiedono su disco. In seguito alla configurazione, ogni slave provvede a munirsi dell’input necessario allo svolgimento del task ad esso assegnato, procedendo con letture dal disco: ogni slave si preoccupa di leggere il file eseguibile FASTA presente su disco, ed i file di input per quest’ultimo. Dalle immagini si può notare come l’aumento del numero di slave sia inversamente proporzionale al numero di accessi al disco, in quanto ogni slave è incaricato allo svolgimento di un numero inferiore di MapTask, e quindi ha bisogno di un minor numero di letture. 5.3.4.2 Scrittura Figura 5.10 Figura 5.11 Capitolo 5: Tests e Benchmarking 33 Figura 5.12 I grafici mostrati, presentano le operazioni di scrittura necessarie durante l’esecuzione di un singolo job. Nella prima sezione di ogni grafico, come nel caso della lettura, è mostrato l’avvio del framework Hadoop, che richiede scritture dovute al caricamento dell’input sull’HDFS, che in questo caso risulta essere molto breve in quanto i dati da caricare risultano essere di dimensioni molto contenute, la sua formattazione e la scrittura dei log di sistema. Durante l’esecuzione dei job, gli slaves effettuano scritture continue sul disco in quanto l’output del processo FASTA è redirezionato su file, che successivamente sarà caricato sull’HDFS. 5.3.5 Pacchetti di Rete e Throughput Di seguito sono presentati i grafici relativi allo scambio di pacchetti ed al throughput durante un job, al variare del numero di slave. Tali grafici sono suddivisi in Capitolo 5: Tests e Benchmarking traffico in ingresso e traffico in uscita. 5.3.5.1 IN Figura 5.13 Figura 5.14 Figura 5.15 34 Capitolo 5: Tests e Benchmarking 35 Figura 5.16 Figura 5.17 Figura 5.18 I grafici mostrati, presentano il numero di pacchetti ricevuti e la quantità di traffico in entrata misurata in KB/s, durante un singolo job. Capitolo 5: Tests e Benchmarking 36 Le immagini mostrano come, il numero di creste è pari al numero di MapTask da eseguire per ogni slave. Si nota che, il numero di pacchetti ricevuti dagli slave e dall’Application Master è sempre maggiore all’inizio di ogni MapTask. In particolare l’Application Master è la principale destinazione dei pacchetti, in quanto tutti gli slave comunicano con esso per essere orchestrati nell’esecuzione dei task. Da notare, che durante l’intera esecuzione del job, sia l’Application Master che gli slave continuano a ricevere un basso numero di pacchetti, presumibilmente messaggi di heart beat. Inoltre, la quantità di pacchetti ricevuti dall’Application Master è inversamente proporzionale al numero di slave, in quanto per un singolo job, aumentano i MapTask per slave. 5.3.5.2 OUT Figura 5.19 Figura 5.20 Capitolo 5: Tests e Benchmarking Figura 5.21 Figura 5.22 Figura 5.23 Figura 5.24 37 Capitolo 5: Tests e Benchmarking 38 I grafici mostrati, presentano il numero di pacchetti inviati e la quantità di traffico in uscita misurata in KB/s, durante un singolo job. Come nei grafici precedenti, si ha un numero di creste pari al numero di MapTask per slave. Si nota che l’Application Master è il nodo che ha un maggior numero di pacchetti in uscita. Inoltre, l’invio costante di pacchetti da parte degli slave rispecchia il fatto che durante l’elaborazione della coppia di genomi, vi sia la comunicazione dell’avanzamento del task, grazie all’invocazione del metodo progress offerto dal contesto del Mapper. Probabilmente l’intervallo di campionamento utilizzato non ha permesso di ottenere delle statistiche accurate per quanto riguarda il test a 32 nodi, in quanto non è visibile il picco di pacchetti inviati dall’Application Master, e si crede sia dovuto alla breve durata del job. 5.3.6 Anomalia riscontrata I grafici riguardanti l’utilizzo di CPU con 8, 16 e 32 nodi, mostrano la presenza di un singolo job, avente un utilizzo di CPU di gran lunga inferiore ai restanti, come è evidenziato dalla figura 5.25. L’evento sospetto ha portato ad analizzare i log dell’esperimento, in particolare di quello ad 8 nodi. Da tale analisi si è riscontrato che vi era un file il cui tempo di esecuzione totale risultava essere ben inferiore ai restanti. Figura 5.25 Capitolo 5: Tests e Benchmarking 39 Il file in questione è denominato GEN-Methanocaldococcus-jannaschii-DSM-2661chromosome.txt e come è mostrato nello scorcio sottostante, è risultato non rispettare il formato FASTA. >sp|GEN|0 0 OS=GEN_Methanocaldococcus_jannaschii_DSM_2661_chromosome GN=0 >gi|15668172|ref|NC_000909.1| Methanocaldococcus jannaschii DSM 2661 chromosome, complete genome TACATTAGTGTTTATTACATTGAGAAACTTTATAATTAAAAAAGATTCATGTAAATTTCTTATTTGTTTA ... Tale file ha causato errore nel processo FASTA dei MapTask in cui esso è un elemento della coppia in input, e maggiormente nel job in cui è scelto come file TARGET. La medesima situazione si è presentata anche nell’esperimento sequenziale, per cui si ritiene che i tempi impiegati siano comunque confrontabili, nonostante l’incidente. 5.3.7 Analisi Prestazione 5.3.7.1 Speedup Figura 5.26 Capitolo 5: Tests e Benchmarking 5.3.7.2 40 Efficienza Figura 5.27 I grafici mostrano come, lo speedup calcolato sia buono per 8 nodi, meno a 16, ed a 32. Ciò è dovuto principalmente alla quantità di file forniti in input all’applicazione, la quale risulta essere bassa per un test a 32 nodi. Infatti, un risultato come quello ottenuto, era stato immaginato conoscendo la natura dell’applicazione, pensata e costruita per effettuare un gran numero di confronti. Capitolo 5: Tests e Benchmarking 41 La dimensione dei singoli file, inoltre, era esigua rispetto al tempo impiegato dall’eseguibile FASTA nel processare una singola coppia. Tale decisione, però, è stata necessaria per poter ottenere un riscontro in tempo ragionevole da parte della versione sequenziale. Lo scarso speedup ottenuto a 16 e 32 nodi è confermato dall’alta efficienza ottenuta nell’esecuzione ad 8 nodi. Anche dai grafici relativi all’utilizzo della CPU si può notare come nell’esecuzione ad 8 nodi i processori a disposizione siano stati sfruttati maggiormente. Capitolo 6 Conclusioni Molti dei problemi appartenenti al mondo della biologia e che si affacciano a quello dell’informatica, richiedono elevata potenza di calcolo e memoria. Nel documento è stata discussa un’applicazione che sfrutta il paradigma MapReduce ed il framework Hadoop per risolvere uno di questi, il Pairwise Sequence Alignment. Tale applicazione si avvale della computazione distribuita per effettuare confronti tra sequenze di genomi. Come si è evidenziato nel capitolo 2.1, l’allineamento di sequenze ha una natura sequenziale, difficile da distribuire. Tale fattore in aggiunta al fattore tempo ha fatto sì che la soluzione fosse quella di distribuire i confronti, e non più il singolo allineamento. Da tale idea nasce l’applicazione descritta nel documento. Essa mira a massimizzare il numero di confronti tra un file di riferimento e un vasto insieme di file candidati. I risultati mostrano come tale idea necessiti di un elevato numero di file in input, ognuno dei quali rappresentante un lungo genoma e di conseguenza avente maggiori dimensioni, ciò sta a significare che l’idea funzionerebbe in uno scenario del mondo reale. L’applicazione potrebbe essere migliorata avendo un input come quello descritto precedentemente, valutando inoltre diversi metodi di suddivisione dell’input, per poi applicare quello che risulti portare un incremento di efficienza e potendo essere eseguita su un numero maggiore di nodi. In aggiunta, l’eseguibile FASTA potrebbe sfruttare meglio il suo parallelismo interno se fosse eseguito su commodity hardware che riesca a mostrare maggiormente le sue potenzialità su multi-core. 42 Bibliografia [1] W.R. Pearson, D.J. Lipman, Improved tools for biological sequence comparison, 1988, disponibile all’indirizzo: http://www.ncbi.nlm.nih.gov/ pmc/articles/PMC280013/pdf/pnas00260-0036.pdf [2] Apache Hadoop, http://hadoop.apache.org/ [3] Ron Shamir, Eti Ezra, Guy Gelles, http://www.cs.tau.ac.il/ ~rshamir/algmb/98/scribe/pdf/lec02.pdf [4] Smith - Waterman Pairwise Alignment Algorithm, http://www.stat. purdue.edu/~junxie/topic2.pdf [5] Codice sorgente FASTA3.6, http://faculty.virginia.edu/wrpearson/ FASTA/CURRENT/ [6] Pseudo-algoritmo FASTA, http://ab.inf.uni-tuebingen.de/ teaching/ws06/albi1/script/BLAST_slides.pdf [7] Pseudo-algoritmo FASTA, http://www.cs.helsinki.fi/ bioinformatiikka/mbi/courses/07-08/itb/slides/itb0708_slides_ 83-116.pdf [8] Formato FASTA, http://en.wikipedia.org/wiki/FASTA_format [9] VMWare Inc., http://www.vmware.com/ [10] Dstat: Versatile resource home-made/dstat/ statistics 43 tool, http://dag.wiee.rs/ Appendice A Appendice A.1 Link al codice sorgente L’intero codice sorgente presentato in questo documento è disponibile online sulla piattaforma GitHub: • Il codice relativo al progetto jFasta è disponibile all’indirizzohttps://github. com/indiependente/jfasta • Il codice relativo al progetto Fasta MapReduce è invece accessibile all’indirizzo https://github.com/indiependente/fastamapreduce In entrambi i repository sono presenti i file per importare i progetti nell’IDE Eclipse. 44