Apache HBase ist die Hadoop-Datenbank und basiert auf dem Hadoop Distributed File System (HDFS ). HBase ermöglicht den wahlfreien Zugriff auf und die Aktualisierung von in HDFS gespeicherten Daten, aber Dateien in HDFS können nur angehängt werden und sind unveränderlich, nachdem sie erstellt wurden. Sie fragen sich also vielleicht, wie bietet HBase Lese- und Schreibvorgänge mit geringer Latenz? In diesem Blogbeitrag erläutern wir dies, indem wir den Schreibpfad von HBase beschreiben – wie Daten in HBase aktualisiert werden.
Der Schreibpfad So vervollständigt eine HBase Put- oder Delete-Operationen. Dieser Pfad beginnt bei einem Client, bewegt sich zu einem Regionsserver und endet, wenn Daten schließlich in eine HBase-Datendatei namens HFile geschrieben werden . Im Entwurf des Schreibpfads sind Funktionen enthalten, die HBase verwendet, um Datenverluste im Falle eines Ausfalls eines Regionsservers zu verhindern. Daher kann das Verständnis des Schreibpfads einen Einblick in den nativen Mechanismus zur Verhinderung von Datenverlust von HBase geben.
Jede HBase-Tabelle wird von Servergruppen gehostet und verwaltet, die in drei Kategorien fallen:
- Ein aktiver Master-Server
- Ein oder mehrere Backup-Master-Server
- Viele Regionsserver
Regionsserver tragen zur Handhabung der HBase-Tabellen bei. Da HBase-Tabellen sehr groß sein können, werden sie in Partitionen unterteilt, die als Regionen bezeichnet werden. Jeder Regionsserver verwaltet eine oder mehrere dieser Regionen. Beachten Sie, dass ein Absturz des Master-Servers keinen Datenverlust verursachen kann, da Regionsserver die einzigen Server sind, die HBase-Tabellendaten bereitstellen.
HBase-Daten sind ähnlich wie eine sortierte Karte organisiert, wobei der sortierte Schlüsselbereich in verschiedene Shards oder Regionen unterteilt ist. Ein HBase-Client aktualisiert eine Tabelle, indem er Put- oder Delete-Befehle aufruft. Wenn ein Client eine Änderung anfordert, wird diese Anfrage standardmäßig sofort an einen Regionsserver weitergeleitet. Ein Client kann die Änderungen jedoch programmgesteuert auf der Clientseite zwischenspeichern und diese Änderungen in einem Stapel auf Regionsserver übertragen, indem er die automatische Bereinigung deaktiviert. Wenn Autoflush deaktiviert ist, werden die Änderungen zwischengespeichert, bis Flush-Commits aufgerufen wird oder der Puffer voll ist, abhängig von der Puffergröße, die programmgesteuert oder mit dem Parameter „hbase.client.write.buffer“ konfiguriert wurde.
Da der Zeilenschlüssel sortiert ist, lässt sich leicht feststellen, welcher Regionsserver welchen Schlüssel verwaltet. Eine Änderungsanforderung gilt für eine bestimmte Zeile. Jeder Zeilenschlüssel gehört zu einer bestimmten Region, die von einem Regionsserver bedient wird. Basierend auf dem Put- oder Delete-Schlüssel kann ein HBase-Client also einen geeigneten Regionsserver finden. Zuerst sucht es die Adresse des Regionsservers, der die Region -ROOT- aus dem ZooKeeper-Quorum hostet. Vom Stammregionsserver findet der Client den Standort des Regionsservers heraus, der die -META-Region hostet. Vom Meta-Regionsserver aus lokalisieren wir schließlich den eigentlichen Regionsserver, der die angeforderte Region bedient. Dies ist ein dreistufiger Prozess, sodass der Standort der Region zwischengespeichert wird, um diese kostspielige Reihe von Vorgängen zu vermeiden. Wenn der im Cache gespeicherte Standort ungültig ist (z. B. eine Ausnahme wegen einer unbekannten Region), ist es an der Zeit, die Region neu zu lokalisieren und den Cache zu aktualisieren.
Nachdem die Anfrage vom richtigen Regionsserver empfangen wurde, kann die Änderung nicht sofort in eine HFile geschrieben werden, da die Daten in einer HFile nach dem Zeilenschlüssel sortiert werden müssen. Dies ermöglicht eine effiziente Suche nach zufälligen Zeilen beim Lesen der Daten. Daten können nicht zufällig in die HFile eingefügt werden. Stattdessen muss die Änderung in eine neue Datei geschrieben werden. Wenn jedes Update in eine Datei geschrieben würde, würden viele kleine Dateien erstellt. Eine solche Lösung wäre weder skalierbar noch effizient, um sie zu einem späteren Zeitpunkt zusammenzuführen oder auszulesen. Daher werden Änderungen nicht sofort in ein neues HFile geschrieben.
Stattdessen wird jede Änderung an einem Ort im Speicher gespeichert, der als Memstore bezeichnet wird , das zufällige Schreibvorgänge kostengünstig und effizient unterstützt. Daten im Speicher werden auf die gleiche Weise sortiert wie Daten in einer HFile. Wenn der Speicher genügend Daten angesammelt hat, wird der gesamte sortierte Satz in eine neue HFile in HDFS geschrieben. Das Abschließen einer großen Schreibaufgabe ist effizient und nutzt die Stärken von HDFS.
Obwohl das Schreiben von Daten in den Memstore effizient ist, bringt es auch ein Risikoelement mit sich:Im Memstore gespeicherte Informationen werden im flüchtigen Speicher gespeichert, sodass bei einem Systemausfall alle Memstore-Informationen verloren gehen. Um dieses Risiko zu mindern, speichert HBase Aktualisierungen in einem Write-Ahead-Log (WAL ), bevor die Informationen in den Speicher geschrieben werden. Wenn ein Regionsserver ausfällt, können auf diese Weise Informationen, die im Speicher dieses Servers gespeichert waren, aus seiner WAL wiederhergestellt werden.
Hinweis:Standardmäßig ist WAL aktiviert, aber das Schreiben der WAL-Datei auf die Festplatte verbraucht einige Ressourcen. WAL kann deaktiviert werden, dies sollte jedoch nur erfolgen, wenn das Risiko eines Datenverlusts unbedenklich ist. Wenn Sie sich dafür entscheiden, WAL zu deaktivieren, erwägen Sie die Implementierung Ihrer eigenen Notfallwiederherstellungslösung oder seien Sie auf die Möglichkeit eines Datenverlusts vorbereitet.
Die Daten in einer WAL-Datei sind anders organisiert als in HFile. WAL-Dateien enthalten eine Liste von Bearbeitungen, wobei eine Bearbeitung ein einzelnes Put oder Delete darstellt. Die Bearbeitung enthält Informationen über die Änderung und die Region, für die die Änderung gilt. Bearbeitungen werden chronologisch geschrieben, sodass Ergänzungen aus Gründen der Persistenz an das Ende der WAL-Datei angehängt werden, die auf der Festplatte gespeichert ist. Da WAL-Dateien chronologisch geordnet sind, besteht keine Notwendigkeit, an einer zufälligen Stelle innerhalb der Datei zu schreiben.
Wenn WALs wachsen, werden sie schließlich geschlossen und eine neue, aktive WAL-Datei wird erstellt, um weitere Bearbeitungen zu akzeptieren. Dies wird als „Rollen“ der WAL-Datei bezeichnet. Sobald eine WAL-Datei gerollt ist, werden keine weiteren Änderungen an der alten Datei vorgenommen.
Standardmäßig wird die WAL-Datei gerollt, wenn ihre Größe etwa 95 % der HDFS-Blockgröße beträgt. Sie können den Multiplikator mit dem Parameter „hbase.regionserver.logroll.multiplier“ und die Blockgröße mit dem Parameter „hbase.regionserver.hlog.blocksize“ konfigurieren. Die WAL-Datei wird auch regelmäßig basierend auf dem konfigurierten Intervall „hbase.regionserver.logroll.period“ gerollt, standardmäßig eine Stunde, selbst wenn die Größe der WAL-Datei kleiner als das konfigurierte Limit ist.
Die Einschränkung der WAL-Dateigröße erleichtert eine effiziente Dateiwiedergabe, wenn eine Wiederherstellung erforderlich ist. Dies ist besonders wichtig während der Wiedergabe der WAL-Datei einer Region, da während der Wiedergabe einer Datei die entsprechende Region nicht verfügbar ist. Die Absicht besteht darin, schließlich alle Änderungen aus jeder WAL-Datei auf die Festplatte zu schreiben und diesen Inhalt in einer HFile beizubehalten. Danach kann die WAL-Datei archiviert werden und wird schließlich vom LogCleaner-Daemon-Thread gelöscht. Beachten Sie, dass WAL-Dateien als Schutzmaßnahme dienen. WAL-Dateien müssen nur wiedergegeben werden, um Aktualisierungen wiederherzustellen, die andernfalls nach einem Absturz eines Regionsservers verloren gehen würden.
Ein Regionsserver bedient viele Regionen, verfügt jedoch nicht über eine WAL-Datei für jede Region. Stattdessen wird eine aktive WAL-Datei von allen Regionen gemeinsam genutzt, die vom Regionsserver bedient werden. Da WAL-Dateien regelmäßig gerollt werden, kann ein Regionsserver viele WAL-Dateien haben. Beachten Sie, dass es zu einem bestimmten Zeitpunkt nur eine aktive WAL pro Regionsserver gibt.
Unter der Annahme des standardmäßigen HBase-Stammverzeichnisses „/hbase“ werden alle WAL-Dateien für eine Regionsserverinstanz im gleichen Stammverzeichnis gespeichert, das wie folgt lautet:
/hbase/.logs/<host>, <port>,<startcode>
Zum Beispiel:
/hbase/.logs/srv.example.com,60020,1254173957298
WAL-Protokolldateien werden wie folgt benannt:
/hbase/.logs/<host>, <port>,<startcode>/<host>%2C <port>%2C<startcode>.<timestamp>
Zum Beispiel:
/hbase/.logs/srv.example.com,60020,1254173957298/srv.example.com%2C60020%2C1254173957298.1254173957495
Jede Bearbeitung in der WAL-Datei hat eine eindeutige Sequenz-ID. Diese ID wird erhöht, um die Reihenfolge der Bearbeitungen beizubehalten. Immer wenn eine Protokolldatei gerollt wird, werden die nächste Sequenz-ID und der alte Dateiname in eine speicherinterne Zuordnung gestellt. Diese Informationen werden verwendet, um die maximale Sequenz-ID jeder WAL-Datei zu verfolgen, sodass wir leicht herausfinden können, ob eine Datei zu einem späteren Zeitpunkt archiviert werden kann, wenn ein Speicher auf die Festplatte geleert wird.
Bearbeitungen und ihre Sequenz-IDs sind innerhalb einer Region eindeutig. Jedes Mal, wenn eine Bearbeitung zum WAL-Protokoll hinzugefügt wird, wird die Sequenz-ID der Bearbeitung auch als letzte geschriebene Sequenz-ID aufgezeichnet. Wenn der Speicher auf die Platte geleert wird, wird die letzte für diese Region geschriebene Sequenz-ID gelöscht. Wenn die letzte auf die Platte geschriebene Sequenz-ID dieselbe ist wie die maximale Sequenz-ID einer WAL-Datei, kann daraus geschlossen werden, dass alle Bearbeitungen in einer WAL-Datei für diese Region auf die Platte geschrieben wurden. Wenn alle Bearbeitungen für alle Regionen in einer WAL-Datei auf die Festplatte geschrieben wurden, ist klar, dass kein Teilen oder erneutes Abspielen erforderlich ist und die WAL-Datei archiviert werden kann.
WAL File Rolling und Memstore Flush sind zwei getrennte Aktionen und müssen nicht zusammen stattfinden. Wir möchten jedoch nicht zu viele WAL-Dateien pro Regionsserver aufbewahren, um eine zeitaufwändige Wiederherstellung zu vermeiden, falls ein Regionsserver ausfällt. Daher prüft HBase beim Rollen einer WAL-Datei, ob zu viele WAL-Dateien vorhanden sind, und entscheidet, welche Regionen geleert werden sollen, damit einige WAL-Dateien archiviert werden können.
In diesem Beitrag erläutern wir den HBase-Schreibpfad, mit dem Daten in HBase erstellt und/oder aktualisiert werden. Einige wichtige Teile davon sind:
- Wie ein Client einen Regionsserver findet
- Memstore, der schnelle zufällige Schreibvorgänge unterstützt,
- WAL-Dateien zur Vermeidung von Datenverlusten bei Serverausfällen in der Region.
Wir werden in späteren Beiträgen über HFile-Formate, WAL-Datei-Splitting und so weiter sprechen.