Dieser Artikel analysiert hauptsächlich den Lese- und Schreibblockprozess des Hadoop-Clients sowie das Kommunikationsprotokoll zwischen Client und Datenknoten, das Datenflussformat usw.
Der Hadoop-Client kommuniziert mit dem Namensknoten über das RPC-Protokoll, der Client verwendet jedoch nicht RPC für die Kommunikation mit dem Datenknoten, sondern verwendet direkt den Socket. Die Protokolle zum Lesen und Schreiben sind ebenfalls unterschiedlich. In diesem Artikel wird Hadoop Version 0.20.2 analysiert. Version 0.19 ist das gleiche.) Das Prinzip und das Kommunikationsprotokoll der Kommunikation zwischen Client und Datenknoten. Es sollte auch betont werden, dass sich das Kommunikationsprotokoll zwischen Client und Datenknoten in den Versionen 0.23 und höher geändert hat. Verwenden Sie Protobuf als Serialisierungsmethode.
Schreibblock
1. Der Client fordert den Namensknoten zunächst über namenode.create auf, eine Datei zu erstellen, und startet dann den DataStreamer-Thread.
2. Der Client umfasst drei Threads. Der Hauptthread ist dafür verantwortlich, lokale Daten in den Speicher zu lesen, sie in ein Paketobjekt zu kapseln und sie in die Warteschlange dataQueue zu stellen.
3. Der dataStreamer-Thread erkennt, ob die Warteschlange dataQueue über ein Paket verfügt. Wenn ja, erstellt er zunächst ein BlockOutPutStream-Objekt (ein Block wird einmal erstellt und ein Block kann mehrere Pakete enthalten. Wenn er erstellt wird, kommuniziert er mit dem entsprechenden Datenknoten.) die DATA_TRANSFER_HEADER-Informationen und ruft die Rückgabe ab. Erstellen Sie dann einen ResponseProcessor-Thread, der für den Empfang der vom Datenknoten zurückgegebenen Bestätigungsinformationen und die Behandlung von Fehlern verantwortlich ist.
4. Der dataStreamer entnimmt das Package-Objekt aus der dataQueue und sendet es an den datanode. Anschließend wird die Schleife fortgesetzt, um zu ermitteln, ob die dataQueue über Daten verfügt.
Die folgende Abbildung zeigt den Prozess des Schreibblocks.
Die folgende Abbildung zeigt das Format der Nachricht
Block lesen
Hauptsächlich in der BlockReader-Klasse implementiert.
Beim Initialisieren von newBlockReader,
1. Erstellen Sie einen neuen SocketOutputStream (Socket, Timeout), indem Sie den Sock-Parameter übergeben, und schreiben Sie dann die Kommunikationsinformationen, die sich vom Schreiben des Blockheaders unterscheiden.
//den Header schreiben.
out.writeShort( DataTransferProtocol. DATA_TRANSFER_VERSION );
out.write( DataTransferProtocol. OP_READ_BLOCK );
out.writeLong( blockId );
out.writeLong(genStamp);
out.writeLong( startOffset );
out.writeLong(len);
Text.writeString (out, clientName);
out.flush();
2. Erstellen Sie den Eingabestream new SocketInputStream(socket, timeout)
3. Bestimmen Sie die Rückgabenachricht in.readShort() != DataTransferProtocol
4. Erstellen Sie eine Prüfsumme basierend auf dem Eingabestream: DataChecksum checksum = DataChecksum.newDataChecksum( in )
5. Lesen Sie die Position des ersten Chunks: long firstChunkOffset = in.readLong()
Hinweis: 512 Bytes werden verwendet, um die Prüfsumme für einen Block (4 Bytes) zu berechnen.
6. Lesen Sie als Nächstes die spezifischen Daten in der Lesemethode von BlockReader: result = readBuffer(buf, off, realLen)
7. Lesen Sie Stück für Stück
int packetLen = in.readInt();
long offsetInBlock = in.readLong();
long seqno = in.readLong();
boolean lastPacketInBlock = in.readBoolean();
int dataLen = in.readInt();
IOUtils.readFully (in, checksumBytes.array(), 0,
checksumBytes.limit());
IOUtils.readFully (in, buf, offset, chunkLen);
8. Prüfsummenüberprüfung nach dem Lesen der Daten;