HDFS-Tutorial: ArchiTektur, Lesen und Schreiben OperaProduktion

⚡ Intelligente Zusammenfassung

HDFS ist die verteilte Speicherschicht von Hadoop, die sehr große Dateien in replizierte Blöcke auf Standardrechnern aufteilt, sodass ein einzelner NameNode tracks-Metadaten, während viele DataNodes Lese- und Schreibanfragen zuverlässig bedienen.

  • 🔘 ArchiStruktur: Der NameNode speichert das Namespace-Image und das Bearbeitungsprotokoll, während die DataNodes die eigentlichen Blockrepliken speichern.
  • ☑️ Blockgröße: Hadoop 1.x verwendete standardmäßig 64 MB große Blöcke; Hadoop 2.x und 3.x verwenden stattdessen standardmäßig 128 MB.
  • Reproduzieren: Standardmäßig werden drei Replikate pro Block angelegt, verteilt auf mehrere Racks, sodass bei einem Hardwareausfall niemals Daten verloren gehen.
  • 🧪 Lesepfad: FSDataInputStream und DFSInputStream rufen Blockpositionen vom NameNode ab und streamen dann Bytes direkt von den DataNodes.
  • Schreibpfad: DFSOutputStream reiht Pakete in eine Warteschlange ein, DataStreamer erstellt eine DataNode-Pipeline, und eine Ack-Queue schützt vor Paketverlust.
  • 🧭 Zugriffsmöglichkeiten: Das org.apache.hadoop.fs Java Sowohl die API als auch die HDFS-DFS-Shell decken die Vorgänge Öffnen, Lesen, Schreiben und Schließen ab.

HDFS-Tutorial

Was ist HDFS?

HDFS ist ein verteiltes Dateisystem zur Speicherung sehr großer Datendateien, das auf Clustern handelsüblicher Hardware läuft. Es ist fehlertolerant, skalierbar und extrem einfach erweiterbar. Hadoop wird standardmäßig mit HDFS (Hadoop Distributed File System) ausgeliefert.

Wenn die Daten die Speicherkapazität einer einzelnen physischen Maschine überschreiten, ist es unerlässlich, sie auf mehrere separate Maschinen zu verteilen. Ein Dateisystem, das speicherspezifische Vorgänge über ein Netzwerk von Maschinen verwaltet, wird als verteiltes Dateisystem bezeichnet. HDFS ist eine solche Software.

HDFS Architektur

Ein HDFS-Cluster besteht im Wesentlichen aus einem NameNode das die Metadaten des Dateisystems verwaltet und Datenknoten die die eigentlichen Daten speichern.

  • Namensknoten: Der NameNode kann als zentraler Knoten des Systems betrachtet werden. Er verwaltet die Dateisystemstruktur und die Metadaten aller Dateien und Verzeichnisse im System. Zwei Dateien, das „Namespace-Image“ und das „Edit-Log“, dienen der Speicherung der Metadaten. Der NameNode kennt alle DataNodes, die Datenblöcke einer bestimmten Datei enthalten, speichert die Blockpositionen jedoch nicht dauerhaft. Diese Informationen werden bei jedem Systemstart anhand der DataNodes neu ermittelt.
  • Datenknoten: DataNodes sind Slave-Knoten, die auf jedem Rechner in einem Cluster installiert sind und den eigentlichen Speicherplatz bereitstellen. Sie sind für die Bearbeitung von Lese- und Schreibanfragen der Clients zuständig.

Da ein einzelner NameNode einen Single Point of Failure darstellen würde, betreiben aktuelle Cluster einen aktiven NameNode neben einem Standby-NameNode, der das Edit-Log über ein Quorum von JournalNodes teilt, mit automatischem Failover zwischen den beiden.

Lese- und Schreibvorgänge in HDFS erfolgen auf Blockebene. Datendateien in HDFS werden in blockgroße Abschnitte unterteilt, die als unabhängige Einheiten gespeichert werden. Die Standardblockgröße beträgt 64 MB in Hadoop 1.x. Ab Hadoop 2.x beträgt die Standardblockgröße 64 MB. dfs.blocksize beträgt 128 MB.

HDFS basiert auf dem Konzept der Datenreplikation, bei dem mehrere Replikate von Datenblöcken erstellt und auf Knoten in einem Cluster verteilt werden, um eine hohe Datenverfügbarkeit im Falle eines Knotenausfalls zu gewährleisten. Der Standardreplikationsfaktor beträgt drei (dfs.replication), und wenn ein DataNode aufhört, Heartbeats zu senden, repliziert der NameNode seine Blöcke automatisch an anderer Stelle neu.

Weißt du es? Eine Datei in HDFS, die kleiner als ein einzelner Block ist, belegt nicht den gesamten Speicher eines Blocks.

Lesen Sie mehr Operation in HDFS

Eine Datenleseanfrage wird von HDFS, dem NameNode und den DataNodes bearbeitet. Wir nennen den Leser einen „Client“. Das folgende Diagramm veranschaulicht den Dateilesevorgang in Hadoop.

HDFS-Leseoperationsdatenfluss zwischen Client, NameNode und DataNodes

  1. Ein Client initiiert eine Leseanforderung durch Aufruf der Methode 'open()' des FileSystem-Objekts; es handelt sich um ein Objekt vom Typ DistributedFileSystem.
  2. Dieses Objekt stellt über RPC eine Verbindung zum NameNode her und ruft Metadaten wie die Speicheradressen der Dateiblöcke ab. Bitte beachten Sie, dass es sich dabei um die Adressen der ersten Blöcke einer Datei handelt.
  3. Als Antwort auf diese Metadatenanfrage werden die Adressen der DataNodes zurückgegeben, die eine Kopie dieses Blocks enthalten.
  4. Sobald die Adressen der DataNodes empfangen wurden, wird ein Objekt vom Typ FSDataInputStream an den Client zurückgegeben. FSDataInputStream enthält DFSInputStream, das die Interaktion mit dem DataNode und dem NameNode übernimmt. In Schritt 4 des obigen Diagramms ruft ein Client die Methode „read()“ auf, wodurch DFSInputStream eine Verbindung zum ersten DataNode herstellt, der den ersten Block einer Datei enthält.
  5. Die Daten werden als Datenströme gelesen, wobei der Client die Methode „read()“ wiederholt aufruft. Dieser Lesevorgang wird so lange fortgesetzt, bis das Ende des Datenblocks erreicht ist.
  6. Sobald das Ende eines Blocks erreicht ist, schließt DFSInputStream die Verbindung und sucht den nächsten DataNode für den nächsten Block.
  7. Sobald der Client mit dem Lesen fertig ist, ruft er die Methode close() auf.

Schreiben Operation in HDFS

In diesem Abschnitt werden wir verstehen, wie Daten über Dateien in HDFS geschrieben werden. Das folgende Diagramm veranschaulicht dies. traces, die den Pfad schreiben.

HDFS-Schreiboperationspipeline mit DataQueue, DataStreamer und Ack Queue

  1. Ein Client initiiert einen Schreibvorgang durch Aufruf der Methode 'create()' des DistributedFileSystem-Objekts, wodurch eine neue Datei erstellt wird – Schritt Nr. 1 im obigen Diagramm.
  2. Das DistributedFileSystem-Objekt stellt über einen RPC-Aufruf eine Verbindung zum NameNode her und initiiert die Erstellung einer neuen Datei. Dieser Dateierstellungsvorgang ordnet der Datei jedoch keine Blöcke zu. Es obliegt dem NameNode zu prüfen, ob die zu erstellende Datei bereits existiert und ob der Client über die erforderlichen Berechtigungen zum Erstellen einer neuen Datei verfügt. Existiert die Datei bereits oder besitzt der Client nicht die erforderlichen Berechtigungen, wird eine IOException ausgelöst. Andernfalls ist der Vorgang erfolgreich und der NameNode erstellt einen neuen Datensatz für die Datei.
  3. Sobald ein neuer Datensatz im NameNode erstellt wurde, wird ein Objekt vom Typ FSDataOutputStream an den Client zurückgegeben. Dieser verwendet es, um Daten in HDFS zu schreiben. Die Datenschreibmethode wird aufgerufen (Schritt 3 im Diagramm).
  4. FSDataOutputStream enthält ein DFSOutputStream-Objekt, das die Kommunikation mit den DataNodes und dem NameNode übernimmt. Während der Client weiterhin Daten schreibt, erstellt DFSOutputStream fortlaufend Pakete mit diesen Daten. Diese Pakete werden in eine Warteschlange, die sogenannte DataQueue, eingereiht.
  5. Es gibt eine weitere Komponente namens DataStreamer, die diese DataQueue verarbeitet. DataStreamer fordert außerdem vom NameNode die Zuweisung neuer Blöcke an und wählt so die für die Replikation geeigneten DataNodes aus.
  6. Nun beginnt der Replikationsprozess mit der Erstellung einer Pipeline mithilfe von DataNodes. In unserem Fall haben wir eine Replikationsebene von 3 gewählt und daher befinden sich 3 DataNodes in der Pipeline.
  7. Der DataStreamer leitet Pakete an den ersten DataNode in der Pipeline weiter.
  8. Jeder DataNode in einer Pipeline speichert das von ihm empfangene Paket und leitet es an den nächsten DataNode in der Pipeline weiter.
  9. Eine weitere Warteschlange, die „Ack Queue“, wird von DFSOutputStream verwaltet, um Pakete zu speichern, die auf eine Bestätigung von den DataNodes warten.
  10. Sobald von allen DataNodes in der Pipeline eine Bestätigung für ein Paket in der Warteschlange empfangen wurde, wird es aus der „Ack-Warteschlange“ entfernt. Im Falle eines DataNode-Fehlers werden Pakete aus dieser Warteschlange verwendet, um den Vorgang erneut zu starten.
  11. Nachdem ein Client das Schreiben von Daten abgeschlossen hat, ruft er die Methode `close()` auf (Schritt 9 im Diagramm). Der Aufruf von `close()` führt dazu, dass die verbleibenden Datenpakete in die Pipeline geschrieben werden, woraufhin auf eine Bestätigung gewartet wird.
  12. Sobald eine abschließende Bestätigung eingegangen ist, wird der NameNode kontaktiert, um ihm mitzuteilen, dass der Schreibvorgang der Datei abgeschlossen ist.

Zugriff auf HDFS über die Java API

In diesem Abschnitt versuchen wir, die Java Schnittstelle für den Zugriff auf das Dateisystem von Hadoop.

Um programmatisch mit dem Dateisystem von Hadoop zu interagieren, bietet Hadoop mehrere Möglichkeiten. Java Das Paket org.apache.hadoop.fs enthält Klassen, die für die Bearbeitung von Dateien im Hadoop-Dateisystem nützlich sind. Zu diesen Operationen gehören Öffnen, Lesen, Schreiben und Schließen. Die Hadoop-Datei-API ist generisch und kann erweitert werden, um mit anderen Dateisystemen als HDFS zu interagieren.

Programmgesteuertes Lesen einer Datei aus HDFS

Objekt java.net.URL wird zum Lesen des Inhalts einer Datei verwendet. Zunächst müssen wir Java Hadoops HDFS erkennen URL Schema. Dies geschieht durch Aufruf der Menge.URLStreamHandlerFactory-Methode auf der URL Objekt und Übergabe einer Instanz von FsUrlStreamHandlerFactory an dieses Objekt. Diese Methode muss nur einmal pro JVM, daher ist es in einem statischen Block eingeschlossen.

Ein Beispielcode ist-

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

Dieser Code öffnet eine Datei und liest ihren Inhalt. Der Pfad dieser Datei auf HDFS wird dem Programm als Kommandozeilenargument übergeben.

Zugriff auf HDFS über die Befehlszeilenschnittstelle

Dies ist eine der einfachsten Möglichkeiten, mit HDFS zu interagieren. Die Befehlszeilenschnittstelle unterstützt Dateisystemoperationen wie das Lesen von Dateien, das Erstellen von Verzeichnissen, das Verschieben von Dateien, das Löschen von Daten und das Auflisten von Verzeichnissen.

Wir können laufen '$HADOOP_HOME/bin/hdfs dfs -help' Um detaillierte Hilfe zu jedem Befehl zu erhalten. Hierbei handelt es sich bei „dfs“ um einen Shell-Befehl von HDFS, der mehrere Unterbefehle unterstützt. In aktuellen Hadoop-Versionen hdfs dfs ist die bevorzugte Form, während die ältere Hadoop-Dateisystem Der Befehl führt die gleiche Arbeit für jedes unterstützte Dateisystem aus.

Nachfolgend sind einige der häufig verwendeten Befehle zusammen mit den jeweiligen Einzelheiten aufgeführt.

1. Kopieren Sie eine Datei vom lokalen Dateisystem nach HDFS

$HADOOP_HOME/bin/hdfs dfs -copyFromLocal temp.txt /

Dieser Befehl kopiert die Datei temp.txt vom lokalen Dateisystem nach HDFS, wie die folgende Ausgabe zeigt.

Der Befehl hdfs dfs -copyFromLocal kopiert die Datei temp.txt nach HDFS.

2. Mit dem Befehl -ls können wir die in einem Verzeichnis vorhandenen Dateien auflisten.

$HADOOP_HOME/bin/hdfs dfs -ls /

In der folgenden Auflistung sehen wir die Datei 'temp.txt' (die zuvor kopiert wurde) im Verzeichnis ' / '.

hdfs dfs -ls Ausgabe listet temp.txt im HDFS-Stammverzeichnis auf

3. Befehl zum Kopieren einer Datei von HDFS in das lokale Dateisystem

$HADOOP_HOME/bin/hdfs dfs -copyToLocal /temp.txt

Dieser Befehl entspricht dem Befehl `-get` und akzeptiert einen expliziten lokalen Zielpfad als zweites Argument. Die folgende Ausgabe zeigt, dass die Datei `temp.txt` in das lokale Dateisystem kopiert wurde.

Die Ausgabe von hdfs dfs -copyToLocal zeigt an, dass temp.txt in das lokale Dateisystem kopiert wurde.

4. Befehl zum Erstellen eines neuen Verzeichnisses

$HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

Der Befehl wird im Hintergrund ausgeführt, wie die untenstehende Eingabeaufforderung zeigt.

Der Befehl hdfs dfs -mkdir erstellt den Ordner /mydirectory in HDFS.

Prüfen Sie, ob das Verzeichnis erstellt wurde oder nicht. Jetzt wissen Sie, wie das geht 😉

Häufig gestellte Fragen

Große Blöcke halten die NameNode-Metadaten klein und ermöglichen es einem Mapper, einen langen sequenziellen Byte-Abschnitt zu lesen, bevor er erneut suchen muss. Die Suchzeit auf der Festplatte wird dadurch zu einem Bruchteil der Übertragungszeit, was die Schnelligkeit vollständiger Dateiscans erklärt.

Der NameNode empfängt keine Heartbeats mehr, markiert den Knoten als ausgefallen und plant die erneute Replikation aller Blöcke, deren Replikationsfaktor unter den festgelegten Wert gefallen ist, auf intakten DataNodes. Laufende Schreibvorgänge werden aus der Bestätigungswarteschlange wiederhergestellt, sodass dem Client keine Pakete verloren gehen.

Nicht in einem korrekt konfigurierten Cluster. HDFS High Availability verwendet einen aktiven und einen Standby-NameNode, die Änderungen über JournalNodes austauschen, und ZooKeeper-Failover-Controller stufen den Standby-NameNode automatisch hoch, wenn der aktive Knoten nicht mehr reagiert.

Beide Funktionen laden Daten in HDFS hoch. Die Option `-copyFromLocal` beschränkt die Quelle auf das lokale Dateisystem, während `-put` jede unterstützte Quelle akzeptiert, einschließlich eines anderen HDFS-Pfads oder der Standardeingabe (stdin). Das Verhalten ist ansonsten identisch; `-copyFromLocal` dokumentiert lediglich die Absicht.

Jede Datei, jedes Verzeichnis und jeder Block belegt Speicherplatz im NameNode, sodass Millionen kleiner Dateien den Heap-Speicher erschöpfen, lange bevor die Festplatten voll sind. Durch die Zusammenfassung in Sequenzdateien, Avro-, ORC-, Parquet- oder HAR-Archiven bleiben die Metadaten überschaubar.

Die Replikation speichert drei vollständige Kopien und benötigt dadurch 200 Prozent mehr Speicherplatz. Erasure Coding, eingeführt in Hadoop 3, speichert stattdessen Paritätszellen und erreicht eine vergleichbare Datensicherheit bei etwa 50 Prozent Mehraufwand. Der günstigere Speicherplatz wird jedoch durch höhere CPU- und Netzwerkkosten während der Wiederherstellung ersetzt.

Maschinelle Lernmodelle, die mit NameNode-Audit-Logs und DataNode-Metriken trainiert wurden, können Kapazitätsengpässe vorhersagen, häufig genutzte Blöcke kennzeichnen und defekte Festplatten erkennen, bevor diese ausfallen. Die Anomalieerkennung von Zugriffsmustern deckt zudem unkontrollierte Prozesse frühzeitig auf.

Copilot vervollständigt schnell bekannten org.apache.hadoop.fs-Boilerplate-Code, wie z. B. FileSystem.get, FSDataInputStream-Schleifen und IOUtils.copyBytes-Aufrufe. Überprüfen Sie den generierten Code immer anhand der verwendeten Hadoop-Version, da sich API-Namen und veraltete Methoden zwischen Hadoop 2.x und 3.x deutlich unterscheiden.

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: