analisi di sequenze genomiche e proteomiche utilizzando Hadoop 2

annuncio pubblicitario
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
Scarica