Apache HBase è il database Hadoop ed è basato sul file system distribuito Hadoop (HDFS ). HBase consente di accedere e aggiornare in modo casuale i dati archiviati in HDFS, ma i file in HDFS possono essere aggiunti solo e sono immutabili dopo la loro creazione. Quindi potresti chiedere, in che modo HBase fornisce letture e scritture a bassa latenza? In questo post del blog, lo spieghiamo descrivendo il percorso di scrittura di HBase:come i dati vengono aggiornati in HBase.
Il percorso di scrittura è il modo in cui un HBase completa le operazioni di inserimento o eliminazione. Questo percorso inizia in un client, si sposta in un server della regione e termina quando i dati vengono infine scritti in un file di dati HBase chiamato HFile . Nella progettazione del percorso di scrittura sono incluse le funzionalità che HBase utilizza per prevenire la perdita di dati in caso di guasto di un server della regione. Pertanto, la comprensione del percorso di scrittura può fornire informazioni sul meccanismo nativo di prevenzione della perdita di dati di HBase.
Ogni tabella HBase è ospitata e gestita da insiemi di server che rientrano in tre categorie:
- Un server principale attivo
- Uno o più server master di backup
- Molti server regionali
I server regionali contribuiscono alla gestione delle tabelle HBase. Poiché le tabelle HBase possono essere di grandi dimensioni, vengono suddivise in partizioni chiamate regioni. Ciascun server di regione gestisce una o più di queste regioni. Tieni presente che poiché i server della regione sono gli unici server che servono i dati della tabella HBase, un arresto anomalo del server master non può causare la perdita di dati.
I dati HBase sono organizzati in modo simile a una mappa ordinata, con lo spazio chiave ordinato suddiviso in partizioni o regioni diverse. Un client HBase aggiorna una tabella richiamando i comandi put o delete. Quando un client richiede una modifica, tale richiesta viene instradata immediatamente a un server regionale per impostazione predefinita. Tuttavia, a livello di codice, un client può memorizzare nella cache le modifiche sul lato client e scaricare queste modifiche nei server dell'area in un batch, disattivando lo svuotamento automatico. Se l'autoflush è disattivato, le modifiche vengono memorizzate nella cache fino a quando non viene richiamato il flush-commits oppure il buffer è pieno a seconda della dimensione del buffer impostata a livello di codice o configurata con il parametro "hbase.client.write.buffer".
Poiché la chiave di riga è ordinata, è facile determinare quale server di regione gestisce quale chiave. Una richiesta di modifica riguarda una riga specifica. Ogni chiave di riga appartiene a una regione specifica servita da un server della regione. Quindi, in base alla chiave di immissione o eliminazione, un client HBase può individuare un server regionale appropriato. Inizialmente, individua l'indirizzo del server della regione che ospita la regione -ROOT- dal quorum ZooKeeper. Dal server della regione radice, il client scopre la posizione del server della regione che ospita la regione -META-. Dal server della meta regione, infine, individuiamo il server della regione effettivo che serve la regione richiesta. Questo è un processo in tre fasi, quindi la posizione della regione viene memorizzata nella cache per evitare questa costosa serie di operazioni. Se la posizione memorizzata nella cache non è valida (ad esempio, otteniamo un'eccezione per una regione sconosciuta), è il momento di riposizionare la regione e aggiornare la cache.
Dopo che la richiesta è stata ricevuta dal server della regione corretta, la modifica non può essere scritta immediatamente in un HFile perché i dati in un HFile devono essere ordinati in base alla chiave di riga. Ciò consente di cercare righe casuali in modo efficiente durante la lettura dei dati. I dati non possono essere inseriti casualmente nell'HFile. Al contrario, la modifica deve essere scritta in un nuovo file. Se ogni aggiornamento fosse scritto su un file, verrebbero creati molti piccoli file. Tale soluzione non sarebbe scalabile né efficiente da unire o leggere in un secondo momento. Pertanto, le modifiche non vengono scritte immediatamente in un nuovo file H.
Invece, ogni modifica viene archiviata in una posizione della memoria denominata memstore , che supporta in modo economico ed efficiente le scritture casuali. I dati nel memstore vengono ordinati allo stesso modo dei dati in un file H. Quando il memstore accumula dati sufficienti, l'intero set ordinato viene scritto in un nuovo file H in HDFS. Il completamento di un'attività di scrittura di grandi dimensioni è efficiente e sfrutta i punti di forza di HDFS.
Sebbene la scrittura dei dati nel memstore sia efficiente, introduce anche un elemento di rischio:le informazioni archiviate nel memstore vengono archiviate nella memoria volatile, quindi se il sistema si guasta, tutte le informazioni del memstore vanno perse. Per ridurre questo rischio, HBase salva gli aggiornamenti in un registro write-ahead (WAL ) prima di scrivere le informazioni su memstore. In questo modo, se un server della regione si guasta, le informazioni che sono state archiviate nel memstore di quel server possono essere recuperate dal suo WAL.
Nota:per impostazione predefinita, WAL è abilitato, ma il processo di scrittura del file WAL su disco consuma alcune risorse. WAL può essere disabilitato, ma questo dovrebbe essere fatto solo se il rischio di perdita di dati non è un problema. Se scegli di disabilitare WAL, prendi in considerazione l'implementazione della tua soluzione di ripristino di emergenza o preparati alla possibilità di perdita di dati.
I dati in un file WAL sono organizzati in modo diverso da HFile. I file WAL contengono un elenco di modifiche, con una modifica che rappresenta una singola immissione o eliminazione. La modifica include informazioni sulla modifica e sulla regione a cui si applica la modifica. Le modifiche vengono scritte in ordine cronologico, quindi, per persistenza, le aggiunte vengono aggiunte alla fine del file WAL memorizzato su disco. Poiché i file WAL sono ordinati cronologicamente, non è mai necessario scrivere in una posizione casuale all'interno del file.
Man mano che i WAL crescono, alla fine vengono chiusi e viene creato un nuovo file WAL attivo per accettare modifiche aggiuntive. Questo è chiamato "rolling" del file WAL. Una volta eseguito il rollio di un file WAL, non vengono apportate ulteriori modifiche al vecchio file.
Per impostazione predefinita, il file WAL viene eseguito il rollio quando la sua dimensione è circa il 95% della dimensione del blocco HDFS. È possibile configurare il moltiplicatore utilizzando il parametro:"hbase.regionserver.logroll.multiplier" e la dimensione del blocco utilizzando il parametro:"hbase.regionserver.hlog.blocksize". Il file WAL viene inoltre aggiornato periodicamente in base all'intervallo configurato "hbase.regionserver.logroll.period", un'ora per impostazione predefinita, anche la dimensione del file WAL è inferiore al limite configurato.
La limitazione delle dimensioni del file WAL facilita la riproduzione efficiente dei file se è necessario un ripristino. Ciò è particolarmente importante durante la riproduzione del file WAL di una regione perché durante la riproduzione di un file, la regione corrispondente non è disponibile. L'intento è infine quello di scrivere tutte le modifiche da ogni file WAL su disco e mantenere quel contenuto in un HFile. Al termine, il file WAL può essere archiviato e infine eliminato dal thread del demone LogCleaner. Si noti che i file WAL servono come misura protettiva. I file WAL devono essere riprodotti solo per recuperare gli aggiornamenti che altrimenti andrebbero persi dopo un arresto anomalo del server della regione.
Un server di regione serve molte regioni, ma non dispone di un file WAL per ciascuna regione. Al contrario, un file WAL attivo viene condiviso tra tutte le regioni servite dal server della regione. Poiché i file WAL vengono trasferiti periodicamente, un server di una regione può avere molti file WAL. Tieni presente che esiste un solo server WAL attivo per regione alla volta.
Assumendo la radice HBase predefinita di "/hbase", tutti i file WAL per un'istanza del server della regione sono archiviati nella stessa cartella radice, che è la seguente:
/hbase/.logs/<host>, <port>,<startcode>
Ad esempio:
/hbase/.logs/srv.example.com,60020,1254173957298
I file di registro WAL sono denominati come segue:
/hbase/.logs/<host>, <port>,<startcode>/<host>%2C <port>%2C<startcode>.<timestamp>
Ad esempio:
/hbase/.logs/srv.example.com,60020,1254173957298/srv.example.com%2C60020%2C1254173957298.1254173957495
Ogni modifica nel file WAL ha un ID sequenza univoco. Questo ID aumenta per preservare l'ordine delle modifiche. Ogni volta che viene eseguito il rollio di un file di registro, l'ID della sequenza successiva e il vecchio nome del file vengono inseriti in una mappa in memoria. Queste informazioni vengono utilizzate per tenere traccia dell'ID sequenza massimo di ciascun file WAL in modo da poter facilmente capire se un file può essere archiviato in un secondo momento, quando alcuni memstore vengono scaricati su disco.
Le modifiche e i relativi ID sequenza sono univoci all'interno di una regione. Ogni volta che viene aggiunta una modifica al registro WAL, anche l'ID sequenza della modifica viene registrato come l'ultima sequenza ID scritta. Quando il memstore viene scaricato su disco, l'ultimo ID sequenza scritto per questa regione viene cancellato. Se l'ultimo ID sequenza scritto su disco è uguale all'ID sequenza massimo di un file WAL, si può concludere che tutte le modifiche in un file WAL per questa regione sono state scritte su disco. Se tutte le modifiche per tutte le regioni in un file WAL sono state scritte su disco, è chiaro che non sarà necessaria alcuna divisione o riproduzione e il file WAL può essere archiviato.
Il rollio del file WAL e lo svuotamento del memstore sono due azioni separate e non devono avvenire insieme. Tuttavia, non vogliamo conservare troppi file WAL per server della regione in modo da evitare un ripristino che richiede tempo in caso di guasto di un server della regione. Pertanto, quando viene eseguito il rollover di un file WAL, HBase controlla se sono presenti troppi file WAL e decide quali regioni devono essere scaricate in modo che alcuni file WAL possano essere archiviati.
In questo post, spieghiamo il percorso di scrittura di HBase, che è il modo in cui i dati in HBase vengono creati e/o aggiornati. Alcune parti importanti di esso sono:
- Come un client individua un server regionale
- Memstore che supporta scritture casuali veloci
- File WAL come metodo per evitare la perdita di dati in caso di guasti del server della regione.
Parleremo dei formati HFile, della divisione dei file WAL e così via nei post successivi.