6.1 Wer hat HBase erfunden und warum?

In diesem Vortrag werden wir über ein so wunderbares Tool wie Hbase sprechen, das in letzter Zeit große Popularität erlangt: Facebook verwendet es beispielsweise als Basis für sein Nachrichtensystem, und das sagt schon viel aus.

In der Vorlesung geht es um das Konzept von Big Table und seine kostenlose Implementierung, Arbeitsmerkmale und Unterschiede sowohl zu klassischen relationalen Datenbanken (wie MySQL und Oracle) als auch zu Schlüsselwertspeichern wie Redis, Aerospike und Memcached. Beginnen wir wie üblich mit der Geschichte des Problems. Wie viele andere BigData-Projekte entstand Hbase aus einem von Google entwickelten Konzept. Die Prinzipien hinter Hbase wurden im Artikel Bigtable: A Distributed Storage System for Structured Data beschrieben .

Wie wir in früheren Vorlesungen besprochen haben, eignen sich gewöhnliche Dateien recht gut für die Stapeldatenverarbeitung mit dem MapReduce-Paradigma. Andererseits ist die Aktualisierung von in Dateien gespeicherten Informationen eher umständlich; Außerdem wird den Dateien die Möglichkeit des wahlfreien Zugriffs entzogen. Für schnelles und bequemes Arbeiten mit Direktzugriff gibt es eine Klasse von NOSQL-Systemen wie Schlüsselwertspeicher, wie Aerospike, Redis, Couchbase, Memcached. Allerdings ist die Stapelverarbeitung in diesen Systemen meist sehr umständlich. Hbase ist ein Versuch, die Bequemlichkeit der Stapelverarbeitung mit der Bequemlichkeit der Aktualisierung und des Direktzugriffs zu kombinieren.

6.2 Datenmodell

HBase ist eine verteilte, spaltenorientierte Multiversion-Schlüsselwertdatenbank.

  • Die Daten werden in Tabellen organisiert, die durch einen Primärschlüssel namens RowKey in Hbase indiziert werden.
  • Für jeden RowKey-Schlüssel kann eine unbegrenzte Menge an Attributen (oder Spalten) gespeichert werden.
  • Spalten sind in Spaltengruppen organisiert, die als Spaltenfamilie bezeichnet werden. In der Regel werden Spalten mit gleichem Verwendungs- und Speichermuster zu einer Spaltenfamilie zusammengefasst.
  • Für jedes Attribut können mehrere unterschiedliche Versionen hinterlegt werden. Verschiedene Versionen haben unterschiedliche Zeitstempel.

Datensätze werden physisch in der nach RowKey sortierten Reihenfolge gespeichert. In diesem Fall werden die Daten, die verschiedenen Spaltenfamilien entsprechen, separat gespeichert, was es bei Bedarf ermöglicht, nur Daten aus der gewünschten Spaltenfamilie zu lesen.

Wenn ein bestimmtes Attribut gelöscht wird, wird es nicht sofort physisch gelöscht, sondern nur mit einem speziellen Tombstone-Flag gekennzeichnet. Die physische Löschung der Daten erfolgt später, wenn der Major Compaction-Vorgang ausgeführt wird.

Attribute, die zu derselben Spaltengruppe gehören und demselben Schlüssel entsprechen, werden physisch als sortierte Liste gespeichert. Jedes Attribut kann für jeden Schlüssel fehlen oder vorhanden sein. Wenn das Attribut fehlt, entsteht kein Mehraufwand für die Speicherung leerer Werte.

Die Listen- und Spaltengruppennamen sind fest vorgegeben und übersichtlich gestaltet. Auf Spaltengruppenebene werden Parameter wie Time to Live (TTL) und die maximale Anzahl gespeicherter Versionen festgelegt. Wenn die Differenz zwischen dem Zeitstempel einer bestimmten Version und der aktuellen Zeit größer als TTL ist, wird der Eintrag zum Löschen markiert. Wenn die Anzahl der Versionen für ein bestimmtes Attribut die maximale Anzahl an Versionen überschreitet, wird der Datensatz ebenfalls zum Löschen markiert.

Das Hbase-Datenmodell kann man sich als Schlüsselwert-Übereinstimmung merken:

<table, RowKey, Column Family, Column, timestamp> -> Value

6.3 Unterstützte Operationen

Die Liste der unterstützten Vorgänge in hbase ist recht einfach. Es werden 4 Hauptoperationen unterstützt:

  • Put : Fügen Sie einen neuen Eintrag zu hbase hinzu. Der Zeitstempel dieses Eintrags kann manuell gesetzt werden, andernfalls wird er automatisch auf die aktuelle Uhrzeit gesetzt.
  • Get : Daten für einen bestimmten RowKey abrufen. Sie können die Spaltenfamilie angeben, aus der wir die Daten entnehmen, sowie die Anzahl der Versionen, die wir lesen möchten.
  • Scannen : Datensätze einzeln lesen. Sie können den Datensatz angeben, von dem aus mit dem Lesen begonnen wird, den Datensatz, in den gelesen werden soll, die Anzahl der zu lesenden Datensätze, die Spaltenfamilie, aus der gelesen werden soll, und die maximale Anzahl von Versionen für jeden Datensatz.
  • Löschen : Markieren Sie eine bestimmte Version zum Löschen. Es erfolgt keine physische Löschung, sie wird auf die nächste große Verdichtung verschoben (siehe unten).

6.4 Architektur

HBase ist eine verteilte Datenbank, die auf Dutzenden oder Hunderten physischer Server ausgeführt werden kann und einen unterbrechungsfreien Betrieb gewährleistet, selbst wenn einige von ihnen ausfallen. Daher ist die Architektur von HBase im Vergleich zu klassischen relationalen Datenbanken recht komplex.

HBase verwendet für seine Arbeit zwei Hauptprozesse:

1. Regionsserver – Bedient eine oder mehrere Regionen. Eine Region ist ein Bereich von Datensätzen, der einem bestimmten Bereich aufeinanderfolgender RowKeys entspricht. Jede Region enthält:

  • Persistenter Speicher ist der Hauptdatenspeicher in HBase. Die Daten werden physisch auf HDFS in einem speziellen HFile-Format gespeichert. Daten in HFile werden in der nach RowKey sortierten Reihenfolge gespeichert. Ein Paar (Region, Spaltenfamilie) entspricht mindestens einer HFIle.
  • MemStore – Schreibpuffer. Da die Daten in HFile d in sortierter Reihenfolge gespeichert werden, ist es recht kostspielig, die HFile pro Datensatz zu aktualisieren. Stattdessen gelangen die Daten beim Schreiben in einen speziellen MemStore-Speicherbereich, wo sie sich für einige Zeit ansammeln. Wenn der MemStore bis zu einem kritischen Wert gefüllt ist, werden die Daten in eine neue HFile geschrieben.
  • BlockCache – Cache zum Lesen. Ermöglicht Ihnen eine erhebliche Zeitersparnis bei häufig gelesenen Daten.
  • Write Ahead Log (WAL) . Da die Daten in den Memstore geschrieben werden, besteht ein gewisses Risiko eines Datenverlusts aufgrund eines Absturzes. Um dies zu verhindern, fallen alle Vorgänge vor der eigentlichen Durchführung der Manipulationen in eine spezielle Protokolldatei. Auf diese Weise können Sie Daten nach einem Fehler wiederherstellen.

2. Master-Server – der Hauptserver im HBase-Cluster. Der Master verwaltet die Verteilung der Regionen auf die Regionsserver, führt ein Register der Regionen, verwaltet den Start regelmäßiger Aufgaben und erledigt andere nützliche Aufgaben.

Um Aktionen zwischen Diensten zu koordinieren, verwendet HBase Apache ZooKeeper, einen speziellen Dienst zum Verwalten von Konfigurationen und Synchronisieren von Diensten.

Wenn die Datenmenge in der Region zunimmt und eine bestimmte Größe erreicht, startet Hbase die Teilung, eine Operation, die die Region um 2 teilt. Um ständige Unterteilungen von Regionen zu vermeiden, können Sie die Grenzen der Regionen voreinstellen und ihr Maximum erhöhen Größe.

Da Daten für eine Region in mehreren HFiles gespeichert werden können, führt Hbase sie regelmäßig zusammen, um die Arbeit zu beschleunigen. Dieser Vorgang wird in Hbase als Komprimierung bezeichnet. Es gibt zwei Arten von Verdichtungen:

  • Leichte Verdichtung . Startet automatisch, läuft im Hintergrund. Hat im Vergleich zu anderen Hbase-Vorgängen eine niedrige Priorität.
  • Große Verdichtung . Der Start erfolgt manuell oder bei bestimmten Auslösern (z. B. durch einen Timer). Es hat eine hohe Priorität und kann den Cluster erheblich verlangsamen. Größere Verdichtungen werden am besten zu einem Zeitpunkt durchgeführt, an dem die Belastung des Clusters gering ist. Bei der Major Compaction werden zuvor mit Tombstone markierte Daten auch physisch gelöscht.

6.5 Möglichkeiten, mit HBase zu arbeiten

HBase-Shell

Der einfachste Weg, mit Hbase zu beginnen, ist die Verwendung des hbase-Shell-Dienstprogramms. Es ist sofort nach der Installation von hbase auf jedem hbase-Clusterknoten verfügbar.

Die Hbase-Shell ist eine Jruby-Konsole mit integrierter Unterstützung für alle grundlegenden Hbase-Vorgänge. Das Folgende ist ein Beispiel für die Erstellung einer Benutzertabelle mit zwei Spaltenfamilien, die Durchführung einiger Änderungen daran und das Löschen der Tabelle am Ende in der hbase-Shell:

create 'users', {NAME => 'user_profile', VERSIONS => 5}, {NAME => 'user_posts', VERSIONS => 1231231231} 
put 'users', 'id1', 'user_profile:name', 'alexander' 
put 'users', 'id1', 'user_profile:second_name', 'alexander' 
get 'users', 'id1' 
put 'users', 'id1', 'user_profile:second_name', 'kuznetsov' 
get 'users', 'id1' 
get 'users', 'id1', {COLUMN => 'user_profile:second_name', VERSIONS => 5} 
put 'users', 'id2', 'user_profile:name', 'vasiliy' 
put 'users', 'id2', 'user_profile:second_name', 'ivanov' 
scan 'users', {COLUMN => 'user_profile:second_name', VERSIONS => 5} 
delete 'users', 'id1', 'user_profile:second_name' 
get 'users', 'id1' 
disable 'users' 
drop 'users'

Native API

Wie die meisten anderen Hadoop-bezogenen Projekte ist hbase in Java implementiert, sodass die native API in Java verfügbar ist. Die Native API ist auf der offiziellen Website ziemlich gut dokumentiert. Hier ist ein Beispiel für die Verwendung der Hbase-API von dort:

import java.io.IOException;

import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

public class MyLittleHBaseClient {
  public static void main(String[] args) throws IOException {
	Configuration config = HBaseConfiguration.create();
	Connection connection = ConnectionFactory.createConnection(config);
	try {
  	Table table = connection.getTable(TableName.valueOf("myLittleHBaseTable"));
  	try {
    	Put p = new Put(Bytes.toBytes("myLittleRow"));
    	p.add(Bytes.toBytes("myLittleFamily"), Bytes.toBytes("someQualifier"),
    	Bytes.toBytes("Some Value"));
    	table.put(p);

    	Get g = new Get(Bytes.toBytes("myLittleRow"));
    	Result r = table.get(g);
    	byte [] value = r.getValue(Bytes.toBytes("myLittleFamily"),
      	Bytes.toBytes("someQualifier"));

    	String valueStr = Bytes.toString(value);
    	System.out.println("GET: " + valueStr);

    	Scan s = new Scan();
    	s.addColumn(Bytes.toBytes("myLittleFamily"), Bytes.toBytes("someQualifier"));
    	ResultScanner scanner = table.getScanner(s);
    	try {
       	for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {
         	System.out.println("Found row: " + rr);
       	}
     	} finally {
       	scanner.close();
     	}
   	} finally {
     	if (table != null) table.close();
   	}
 	} finally {
   	connection.close();
 	}
  }
}

Thrift, REST und Unterstützung für andere Programmiersprachen

Um mit anderen Programmiersprachen arbeiten zu können, stellt Hbase die Thrift-API und die Rest-API bereit. Darauf aufbauend werden Clients für alle wichtigen Programmiersprachen erstellt: Python, PHP, Java Script usw.

6.6 Einige Funktionen der Arbeit mit HBase

  1. Hbase lässt sich sofort in MapReduce integrieren und kann mit dem speziellen TableInputFormat und TableOutputFormat als Ein- und Ausgabe verwendet werden.

  2. Es ist sehr wichtig, den richtigen RowKey auszuwählen. RowKey muss eine gute, gleichmäßige Verteilung über die Regionen hinweg gewährleisten, andernfalls besteht die Gefahr sogenannter „Hot Regions“ – Regionen, die viel häufiger genutzt werden als andere, was zu einer ineffizienten Nutzung der Systemressourcen führt.

  3. Wenn die Daten nicht einzeln, sondern sofort in großen Stapeln hochgeladen werden, unterstützt Hbase einen speziellen BulkLoad-Mechanismus, mit dem Sie Daten viel schneller hochladen können als mit einzelnen Puts. BulkLoad ist im Wesentlichen ein zweistufiger Vorgang:

    • Bildung von HFile ohne Beteiligung von Puts mithilfe eines speziellen MapReduce-Jobs
    • Einfügen dieser Dateien direkt in Hbase
  4. Hbase unterstützt die Ausgabe seiner Metriken an den Ganglia-Überwachungsserver. Dies kann bei der Verwaltung von Hbase sehr hilfreich sein, um Hbase-Problemen auf den Grund zu gehen.

Zeilenschlüssel

Der RowKey ist die Benutzer-ID, bei der es sich um eine GUUID handelt, eine Zeichenfolge, die speziell generiert wurde, um weltweit eindeutig zu sein. GUUIDs werden gleichmäßig verteilt, was eine gute Datenverteilung auf den Servern ermöglicht.

Spaltenfamilie

Unser Speicher verwendet zwei Spaltenfamilien:

  • Daten. In dieser Spaltengruppe werden Daten gespeichert, die für Werbezwecke nicht mehr relevant sind, beispielsweise die Tatsache, dass ein Nutzer bestimmte URLs besucht hat. Die TTL für diese Spaltenfamilie ist auf 2 Monate festgelegt, die Begrenzung der Anzahl der Versionen beträgt 2000.
  • Longdata. In dieser Spaltengruppe werden Daten gespeichert, die im Laufe der Zeit nicht an Relevanz verlieren, wie etwa Geschlecht, Geburtsdatum und andere „ewige“ Benutzermerkmale.

Lautsprecher

Jeder Typ von Benutzerfakten wird in einer separaten Spalte gespeichert. Beispielsweise speichert die Spalte „Data:_v“ die vom Benutzer besuchten URLs und die Spalte „LongData:gender“ speichert das Geschlecht des Benutzers.

Der Zeitstempel dieser Tatsache wird als Zeitstempel gespeichert. In der Spalte „Data:_v“ ist der Zeitstempel beispielsweise der Zeitpunkt, zu dem der Benutzer eine bestimmte URL besucht hat.

Diese Benutzerdatenspeicherstruktur passt sehr gut zu unserem Nutzungsmuster und ermöglicht es Ihnen, Benutzerdaten schnell zu aktualisieren, schnell alle erforderlichen Informationen über Benutzer abzurufen und mithilfe von MapReduce schnell Daten über alle Benutzer auf einmal zu verarbeiten.

6.7 Alternativen

HBase ist recht komplex in der Verwaltung und Nutzung, daher ist es sinnvoll, vor der Nutzung von HBase einen Blick auf die Alternativen zu werfen:

  • Relationale Datenbanken . Eine sehr gute Alternative, insbesondere wenn die Daten auf eine Maschine passen. Außerdem sollten Sie zunächst über relationale Datenbanken nachdenken, wenn Transaktionen mit anderen Indizes als dem Primärindex wichtig sind.

  • Schlüsselwertspeicherung . Speicher wie Redis und Aerospike eignen sich besser, wenn Latenz erforderlich ist und die Stapelverarbeitung weniger wichtig ist.

  • Dateien und deren Bearbeitung mit MapReduce . Wenn die Daten nur hinzugefügt und selten aktualisiert/geändert werden, dann ist es besser, HBase nicht zu verwenden, sondern die Daten einfach in Dateien zu speichern. Um die Arbeit mit Dateien zu vereinfachen, können Sie Tools wie Hive, Pig und Impala verwenden.

Der Einsatz von HBase ist gerechtfertigt, wenn:

  • Es gibt viele Daten, die nicht auf einen Computer/Server passen
  • Daten werden häufig aktualisiert und gelöscht
  • In den Daten gibt es einen expliziten „Schlüssel“, an den sich alles andere bequem binden lässt
  • Stapelverarbeitung erforderlich
  • Benötigt wahlfreien Zugriff auf Daten über bestimmte Schlüssel