Montag , 18 November 2019

Apache HBase mit Microsoft Azure HDInsight (Teil 2)

Apache HBaseNachdem ich bei meinem letzten Blog-Post über Apache HBase mit Microsoft Azure HDInsight eine grobe Einführung in das Thema gegeben habe, möchte ich diesmal auf ein paar Grundlegende Konzepte eingehen…

Aufbau der HBase-Tabellen

Bei HBase-Tabellen sind die Spalten ein zentrales Element:

  • Eine Spalte kann eine oder mehrere Zellen enthalten
  • Eine oder mehrere Spalten setzten sich zu einer Zeile zusammen
  • Eine oder mehrere Zeilen bilden eine Tabelle
  • Jede Zeile hat einen eindeutigen Schlüssel (Row Key), wodurch sie über die API angesprochen werden kann (Dies ist ähnlich dem Primärschlüssel in einem RDBMS).
  • Die Zeilen sind immer nach ihrem Schlüsselwert sortiert.
    Dabei wird die Lexikographische Ordnung angewendet.
    Es wird auf Binärebene verglichen – Byte für Byte – von Links nach Rechts.

Zum besseren Verstandnis, hier ein Beispiel für die Lexikographische Ordnung:

zeile-1 
zeile-10
zeile-11
zeile-2
zeile-20
zeile-21
zeile-a
zeile-ab
zeile-b

 

Soweit klingt das erst mal ähnlich wie bei einem klassischen RDBMS.
Aber nun zu ein paar Besonderheiten:

  • Versionierung

    • Eine Spalte kann mehrere Versionen von Zellen enthalten, welche durch Zeitstempel voneinander getrennt sind.
      Somit enthält jede Tabelle in HBase eine eigene Zeit-Dimension, wodurch sich die verschiedenen Werte der Zellen zu einem angegebenen Zeitfenster abfragen lassen.
    • Wenn bei einer Abfrage keine Zeit angegeben wird, werde immer die aktuellsten Werte zurückgegeben. 
    • Es kann definiert werden, wie viele Versionen behalten werden sollen.
      Auch Definitionen, wie bespielweise "Werte der letzten Woche" sind möglich (Predicate Deletes)
  • Spaltenfamilien

    • Spalten werden in Spaltenfamilien gruppiert
    • Spaltenfamilien werden beim Anlegen einer Tabelle definiert
    • Auf Spaltenfamilien können verschiedene Features angewendet werden, wie beispielsweise die Datenkompression.
    • Alle Spalten in einer Spaltenfamilie werden in der gleichen Datei gespeichert, den sogenannten HFile-Dateien
    • Es sollten nicht zu viele Spaltenfamilien erstellt werden (Im Zweistelligen Bereich).
      Allerdings kann eine Spaltenfamilie Millionen von Spalten enthalten, welche Zellen mit beliebig große Werten enthalten können
  • Transaktionen

    • Transaktionen sind nur innerhalb einer Zeile möglich.
      Somit können Lese-Ändern-Schreib-Vorgänge innerhalb einer Transaktion abgebildet werden.

Zusammengefasst werden Werte in HBase wie folgt abgefragt:
(Tabelle, Zeilen-Schlüssel, Spaltenfamilie, Spalte, Zeitstempel) à Wert

Auto-Sharding

Sogenannte "Regionen" werden in HBase für Skalierbarkeit und die Lastenverteilung genutzt.

Genauer betrachtet sind Regionen zusammenhängende Bereiche von Zeilen.
Diese werden dynamisch vom System aufgeteilt, wenn sie zu groß werden, oder wieder zusammengelegt, um die Anzahl der Dateien zu reduzieren.

Jede Tabelle besteht am Anfang aus einer Region.
Wenn die im System konfigurierte Maximal Größe überschritten wird, wird diese in der Mitte geteilt.
Dabei entstehen zwei halbwegs gleichgroße Regionen.

Das Aufteilen einer Region geschieht asynchron.
Dabei wird solange aus der alten Region gelesen, bis die neuen Regionen vollständig erstellt wurden.

Jede Region wird von exakt einem Region-Server verwaltet.
Jeder Region-Server kann mehrere Regionen verwalten.

Da Regionen nie sonderlich groß werden, können diese schnell von einem Server auf einen Anderen verschoben werden, um Last-Engpässe auszugleichen.
Auch das Wiederherstellen der Regionen eines ausgefallenen Servers ist dadurch zeitnah möglich.

 

HFile-Dateien

Die Daten werden in Blöcken in den HFile-Dateien gespeichert.
Die Standard-Blockgröße ist 64KB, kann aber abgeändert werden.

Am Ende einer jeder Datei wird ein Block-Index angehängt.
Dieser wird beim öffnen der Dateien in den Arbeitsspeicher geladen und dort gehalten.

Somit können Suchvorgänge mit nur einem Dateizugriff abgeschlossen werden.
Dazu wird eine Binärsuche des In-Memory-Block-Index durchgeführt, gefolgt von den Block-Lesevorgang der entsprechenden Datei.

Die Dateien werden im Hadoop-Dateisystem gespeichert (normalerweise das HDFS, aber im Fall von HDInsight im Azure Blob Storage).
Somit ist die Skalierbarkeit und Ausfallsicherheit des Dateisystems gewährleistet.

Bei Schreibvorgängen, werden die Änderungen zuerst in ein Log geschrieben, das sogenannte Write-Ahead-Log (WAL) und anschließend in den Arbeitsspeicher (Memstore) geschrieben.
Sobald die Daten im Memstore eine definierte Menge überschritten haben, werden diese in HFile-Dateien gespeichert und die entsprechenden Log-Daten im WAL verworfen.
Auch dieser Vorgang asynchron im Hintergrund durchgeführt, um schnelle Antwortzeiten zu gewärleisten.

Da auch die Daten im Memstore sortiert gehalten werden, sind somit die Schreibvorgange in die HFile-Dateien schnell abgeschlossen.

Datensätze werden nicht sofort aus den Dateien gelöscht, sondern vorerst mit einer Löschmarkierung (Tombstone Marker) versehen.

Da durch das Persistieren des Memstores immer weitere HFile-Dateien erzeugt werden, führt HBase regelmäßig Bereinigungsaufgaben durch.

Es gibt 2 Arten dieser Bereinigungsaufgaben:

  • Minor Compaction
    Zusammenführen von kleineren HBase-Dateien zu einer großen.
    Da die Daten in sortierter Form vorliegen, geht dieser Vorgang schnell und mit wenig Lese-/Schreibzugriffen
  • Major Compaction
    Alle HFile-Dateien einer Spaltenfamilie (innerhalb einer Region) werden in eine neue HFile-Datei geschrieben.
    Dabei werden auch die Zeilen mit einem Tombstone-Marker oder einem Predicate-Delete gelöscht.