HBase
 sql >> Database >  >> NoSQL >> HBase

I/O Apache HBase – File H

Introduzione

Apache HBase è lo storage manager open source, distribuito e con versione Hadoop adatto per casuale , lettura/scrittura in tempo reale accesso.

Aspetta aspetta? accesso casuale in lettura/scrittura in tempo reale?
Com'è possibile? Hadoop non è solo un sistema di lettura/scrittura sequenziale e di elaborazione batch?

Sì, stiamo parlando della stessa cosa e nei prossimi paragrafi ti spiegherò come HBase ottiene l'I/O casuale, come archivia i dati e l'evoluzione del formato HFile di HBase.

Formati di file I/O di Apache Hadoop

Hadoop viene fornito con un formato di file SequenceFile[1] che puoi utilizzare per aggiungere le tue coppie chiave/valore, ma a causa della funzionalità di sola aggiunta di hdfs, il formato del file non può consentire la modifica o la rimozione di un valore inserito. L'unica operazione consentita è aggiungere e se vuoi cercare una chiave specificata, devi leggere il file finché non trovi la tua chiave.

Come puoi vedere, sei costretto a seguire lo schema di lettura/scrittura sequenziale... ma come è possibile creare un sistema di accesso in lettura/scrittura casuale a bassa latenza come HBase?

Per aiutarti a risolvere questo problema, Hadoop ha un altro formato di file, chiamato MapFile[1], un'estensione di SequenceFile. Il MapFile, in realtà, è una directory che contiene due SequenceFile:il file di dati “/data” e il file di indice “/index”. Il MapFile consente di aggiungere coppie chiave/valore ordinate e ogni N chiavi (dove N è un intervallo configurabile) memorizza la chiave e l'offset nell'indice. Ciò consente una ricerca abbastanza veloce, poiché invece di scansionare tutti i record, esegui la scansione dell'indice che ha meno voci. Una volta trovato il tuo blocco, puoi passare al file di dati reale.

MapFile è utile perché puoi cercare rapidamente coppie chiave/valore ma ci sono ancora due problemi:

  • Come posso eliminare o sostituire una chiave/valore?
  • Quando il mio input non è ordinato, non posso utilizzare MapFile.

HBase e MapFile

La chiave HBase è composta da:la chiave di riga, la famiglia di colonne, il qualificatore di colonna, il timestamp e un tipo.

Per risolvere il problema dell'eliminazione delle coppie chiave/valore, l'idea è quella di utilizzare il campo "tipo" per contrassegnare la chiave come eliminata (marcatori di lapidi). Risolvere il problema della sostituzione delle coppie chiave/valore è solo questione di selezionare il timestamp successivo (il valore corretto è vicino alla fine del file, append significa solo che l'ultimo inserito è vicino alla fine).

Per risolvere il problema della chiave "non ordinata" teniamo in memoria gli ultimi valori-chiave aggiunti. Quando hai raggiunto una soglia, HBase la scarica in un MapFile. In questo modo, finisci per aggiungere chiavi/valori ordinati a un MapFile.

HBase fa esattamente questo[2]:quando aggiungi un valore con table.put(), la tua chiave/valore viene aggiunto al MemStore (sotto il cofano MemStore è un ConcurrentSkipListMap ordinato). Quando viene raggiunta la soglia per-memstore (hbase.hregion.memstore.flush.size) o RegionServer utilizza troppa memoria per i memstore (hbase.regionserver.global.memstore.upperLimit), i dati vengono scaricati su disco come un nuovo MapFile .

Il risultato di ogni flush è un nuovo MapFile, e questo significa che per trovare una chiave devi cercare in più di un file. Questo richiede più risorse ed è potenzialmente più lento.

Ogni volta che viene emesso un get o una scansione, HBase esegue la scansione di ogni file per trovare il risultato, per evitare di saltare troppi file, c'è un thread che rileverà quando hai raggiunto un certo numero di file (hbase.hstore.compaction .max). Quindi prova a unirli insieme in un processo chiamato compattazione, che in pratica crea un nuovo file di grandi dimensioni come risultato dell'unione dei file.

HBase ha due tipi di compattazione:uno chiamato "compattazione minore" che unisce solo due o più piccoli file in uno e l'altro chiamato "compattazione maggiore" che raccoglie tutti i file nella regione, li unisce ed esegue un po' di pulizia. In un'importante compattazione, le chiavi/valori eliminati vengono rimossi, questo nuovo file non contiene gli indicatori di rimozione definitiva e tutte le chiavi/valori duplicati (operazioni di sostituzione dei valori) vengono rimossi.

Fino alla versione 0.20, HBase utilizzava il formato MapFile per memorizzare i dati, ma nella versione 0.20 è stato introdotto un nuovo MapFile specifico per HBase (HBASE-61).

HFile v1

In HBase 0.20, MapFile è sostituito da HFile:un'implementazione di map file specifica per HBase. L'idea è abbastanza simile a MapFile, ma aggiunge più funzionalità di un semplice file chiave/valore. Funzionalità come il supporto per i metadati e l'indice sono ora mantenute nello stesso file.

I blocchi dati contengono le chiavi/valori effettivi come MapFile. Per ogni "operazione di chiusura del blocco" viene aggiunta la prima chiave all'indice e l'indice viene scritto su HFile close.

Il formato HFile aggiunge anche due tipi di blocco "metadati" extra:Meta e FileInfo. Questi due blocchi chiave/valore vengono scritti alla chiusura del file.

Il blocco Meta è progettato per mantenere una grande quantità di dati con la sua chiave come una stringa, mentre FileInfo è una semplice mappa preferita per piccole informazioni con chiavi e valori che sono entrambi array di byte. StoreFile di Regionserver utilizza Meta-Block per memorizzare un filtro Bloom e FileInfo per Max SequenceId, chiave di compattazione principale e informazioni sull'intervallo di tempo. Questa informazione è utile per evitare di leggere il file se non c'è possibilità che la chiave sia presente (Filtro Bloom), se il file è troppo vecchio (Max SequenceId) o se il file è troppo nuovo (Timerange) per contenere ciò che stiamo cercando per.

HFile v2

In HBase 0.92, il formato HFile è stato leggermente modificato (HBASE-3857) per migliorare le prestazioni quando vengono archiviate grandi quantità di dati. Uno dei problemi principali con HFile v1 è che è necessario caricare in memoria tutti gli indici monolitici e i filtri Bloom di grandi dimensioni e per risolvere questo problema v2 introduce indici multilivello e un filtro Bloom a livello di blocco. Di conseguenza, HFile v2  presenta velocità, memoria e utilizzo della cache migliorati.

La caratteristica principale di questa v2 sono i "blocchi in linea", l'idea è quella di rompere l'indice e il filtro Bloom per blocco, invece di avere in memoria l'intero indice e il filtro Bloom dell'intero file. In questo modo puoi tenere nella ram proprio ciò di cui hai bisogno.

Poiché l'indice viene spostato a livello di blocco, si dispone di un indice multilivello, il che significa che ogni blocco ha il proprio indice (leaf-index). L'ultima chiave di ogni blocco viene conservata per creare l'intermedio/indice che rende l'indice multilivello b+albero simile.

L'intestazione del blocco ora contiene alcune informazioni:Il campo “Block Magic” è stato sostituito dal campo “Block Type” che descrive il contenuto del blocco “Data”, Leaf-Index, Bloom, Metadata, Root-Index, ecc. Anche tre sono stati aggiunti i campi (dimensione compressa/non compressa e blocco precedente offset) per consentire ricerche rapide avanti e indietro.

Codifiche a blocchi di dati

Poiché le chiavi sono ordinate e generalmente molto simili, è possibile progettare una compressione migliore di quella che può fare un algoritmo generico.

HBASE-4218 ha cercato di risolvere questo problema e in HBase 0.94 puoi scegliere tra un paio di algoritmi diversi:Prefix e Diff Encoding.

L'idea principale di Prefix Encoding è quella di memorizzare il prefisso comune solo una volta, poiché le righe sono ordinate e l'inizio è in genere lo stesso.

La codifica Diff spinge ulteriormente questo concetto. Invece di considerare la chiave come una sequenza opaca di byte, Diff Encoder divide ogni campo chiave per comprimere ogni parte in un modo migliore. Questo essendo che la famiglia di colonne viene memorizzata una volta. Se la lunghezza della chiave, la lunghezza del valore e il tipo sono gli stessi della riga precedente, il campo viene omesso. Inoltre, per aumentare la compressione, il timestamp memorizzato viene memorizzato come Diff dal precedente.

Si noti che questa funzione è disattivata per impostazione predefinita poiché la scrittura e la scansione sono più lente ma vengono memorizzati nella cache più dati. Per abilitare questa funzione è possibile impostare DATA_BLOCK_ENCODING =PREFIX | DIFF | FAST_DIFF nelle informazioni sulla tabella.

HFile v3

HBASE-5313 contiene una proposta per ristrutturare il layout del file H per migliorare la compressione:

  • Imballa tutte le chiavi insieme all'inizio del blocco e tutto il valore insieme alla fine del blocco. In questo modo puoi utilizzare due diversi algoritmi per comprimere chiave e valori.
  • Comprimi i timestamp usando XOR con il primo valore e usa VInt invece di long.

Inoltre, è allo studio un formato colonnare o una codifica colonnare, dai un'occhiata a AVRO-806 per un formato di file colonnare di Doug Cutting.

Come puoi vedere, la tendenza nell'evoluzione è essere più consapevoli di ciò che contiene il file, per ottenere una migliore compressione o una migliore consapevolezza della posizione che si traduca in meno dati da scrivere/leggere dal disco. Meno I/O significa più velocità!

[1] https://clouderatemp.wpengine.com/blog/2011/01/hadoop-io-sequence-map-set-array-bloommap-files/
[2] https://clouderatemp.wpengine. com/blog/2012/06/hbase-write-path/