I file di piccole dimensioni sono un grosso problema in Hadoop o, almeno, lo sono se il numero di domande nell'elenco degli utenti su questo argomento è qualcosa su cui basarsi. In questo post esaminerò il problema ed esaminerò alcune soluzioni comuni.
Problemi con file di piccole dimensioni e HDFS
Un file di piccole dimensioni è significativamente più piccolo della dimensione del blocco HDFS (64 MB di default). Se stai archiviando file di piccole dimensioni, probabilmente ne hai molti (altrimenti non ti rivolgeresti ad Hadoop) e il problema è che HDFS non può gestire molti file.
Ogni file, directory e blocco in HDFS è rappresentato come un oggetto nella memoria del namenode, ognuno dei quali occupa 150 byte, come regola pratica. Quindi 10 milioni di file, ciascuno con un blocco, consumerebbero circa 3 gigabyte di memoria. Aumentare molto oltre questo livello è un problema con l'hardware attuale. Sicuramente un miliardo di file non è fattibile.
Inoltre, HDFS non è predisposto per accedere in modo efficiente a file di piccole dimensioni:è progettato principalmente per l'accesso in streaming di file di grandi dimensioni. La lettura di file di piccole dimensioni normalmente provoca molte ricerche e molti salti da datanode a datanode per recuperare ogni piccolo file, il che è tutto un modello di accesso ai dati inefficiente.
Problemi con file di piccole dimensioni e MapReduce
Le attività della mappa di solito elaborano un blocco di input alla volta (usando il predefinito FileInputFormat
). Se il file è molto piccolo e ce ne sono molti, ogni attività della mappa elabora pochissimi input e ci sono molte più attività della mappa, ognuna delle quali impone un sovraccarico di contabilità aggiuntivo. Confronta un file da 1 GB suddiviso in 16 blocchi da 64 MB e circa 10.000 file da 100 KB. I 10.000 file utilizzano una mappa ciascuno e il tempo del lavoro può essere decine o centinaia di volte più lento di quello equivalente con un singolo file di input.
Ci sono un paio di funzionalità per alleviare il sovraccarico di contabilità:riutilizzo della JVM delle attività per eseguire più attività di mappa in una JVM, evitando così alcune spese generali di avvio della JVM (consultare il mapred.job.reuse.jvm.num.tasks
proprietà) e MultiFileInputSplit
che può eseguire più di uno split per mappa.
Perché vengono prodotti file di piccole dimensioni?
Ci sono almeno due casi
- I file sono parti di un file logico più grande. Poiché HDFS ha supportato solo di recente le append, un modello molto comune per il salvataggio di file illimitati (ad es. file di registro) è scriverli in blocchi in HDFS.
- I file sono intrinsecamente piccoli. Immagina un grande corpus di immagini. Ogni immagine è un file distinto e non esiste un modo naturale per combinarli in un unico file più grande.
Questi due casi richiedono soluzioni diverse. Nel primo caso, in cui il file è composto da record, il problema può essere evitato chiamando sync()
di HDFS metodo ogni tanto per scrivere continuamente file di grandi dimensioni. In alternativa, è possibile scrivere un programma per concatenare insieme i file di piccole dimensioni.
Per il secondo caso, è necessario un qualche tipo di contenitore per raggruppare i file in qualche modo. Hadoop offre alcune opzioni qui.
File HAR
Gli archivi Hadoop (file HAR) sono stati introdotti in HDFS in 0.18.0 per alleviare il problema di molti file che esercitano pressione sulla memoria del namenode. I file HAR funzionano costruendo un filesystem a più livelli su HDFS. Un file HAR viene creato utilizzando l'hadoop archive
comando, che esegue un processo MapReduce per comprimere i file archiviati in un numero ridotto di file HDFS. Per un client che utilizza il filesystem HAR non è cambiato nulla:tutti i file originali sono visibili e accessibili (sebbene usando un har:// URL). Tuttavia, il numero di file in HDFS è stato ridotto.
La lettura dei file in una HAR non è più efficiente della lettura dei file in HDFS, e in effetti potrebbe essere più lenta poiché ogni accesso ai file HAR richiede due letture del file di indice oltre alla lettura del file di dati (vedi diagramma). E sebbene i file HAR possano essere utilizzati come input per MapReduce, non esiste una magia speciale che consenta alle mappe di operare su tutti i file nel co-residente HAR su un blocco HDFS. Dovrebbe essere possibile creare un formato di input che possa sfruttare la posizione migliorata dei file nelle HAR, ma non esiste ancora. Si noti che MultiFileInputSplit, anche con i miglioramenti in HADOOP-4565 per scegliere i file in una divisione che sono locali del nodo, avrà bisogno di una ricerca per file di piccole dimensioni. Sarebbe interessante vedere le prestazioni di questo rispetto a un SequenceFile, per esempio. Al momento, le HAR sono probabilmente utilizzate al meglio per scopi di archiviazione.
File di sequenza
La solita risposta alle domande sul "problema dei file di piccole dimensioni" è:utilizzare un SequenceFile. L'idea qui è che usi il nome del file come chiave e il contenuto del file come valore. Questo funziona molto bene in pratica. Tornando ai 10.000 file da 100 KB, puoi scrivere un programma per inserirli in un unico SequenceFile, quindi puoi elaborarli in streaming (direttamente o utilizzando MapReduce) operando sul SequenceFile. Ci sono anche un paio di bonus. I SequenceFiles sono divisibili, quindi MapReduce può suddividerli in blocchi e operare su ciascun blocco in modo indipendente. Supportano anche la compressione, a differenza delle HAR. La compressione a blocchi è l'opzione migliore nella maggior parte dei casi, poiché comprime blocchi di più record (anziché per record).
Può essere lento convertire i dati esistenti in SequenceFiles. Tuttavia, è perfettamente possibile creare una raccolta di SequenceFiles in parallelo. (Stuart Sierra ha scritto un post molto utile sulla conversione di un file tar in un SequenceFile — strumenti come questo sono molto utili e sarebbe bello vederne altri). In futuro, è meglio progettare la pipeline di dati per scrivere i dati all'origine direttamente in un SequenceFile, se possibile, piuttosto che scrivere su file di piccole dimensioni come passaggio intermedio.
A differenza dei file HAR, non c'è modo di elencare tutte le chiavi in un SequenceFile, a meno di leggere l'intero file. (MapFiles, che sono come SequenceFiles con chiavi ordinate, mantengono un indice parziale, quindi non possono nemmeno elencare tutte le loro chiavi - vedi diagramma.)
SequenceFile è piuttosto Java-centrico. TFile è progettato per essere multipiattaforma e sostituire SequenceFile, ma non è ancora disponibile.
BaseH
Se stai producendo molti file di piccole dimensioni, a seconda del modello di accesso, potrebbe essere più appropriato un diverso tipo di archiviazione. HBase memorizza i dati in MapFiles (SequenceFiles indicizzati) ed è una buona scelta se è necessario eseguire analisi di streaming in stile MapReduce con occasionali ricerche casuali. Se la latenza è un problema, allora ci sono molte altre scelte:guarda l'eccellente sondaggio di Richard Jones sui negozi chiave-valore.