HDFSDATANODE資料傳輸詳解

zfpigpig發表於2024-03-17

本文主要闡述datanode中一個socket連線接收位元組流的構成,幫助datanode的接收與處理資料。注意hadoop版本為3.1.1。

寫在前面

Datanode本質上也是TCPServer,一般的TCPServer接到客戶端請求以後會分配一個執行緒處理,對於Datanode而言,這個執行緒可以叫做Op處理連線。每個OP連線會多次和客戶端互動,中間涉及多種packet。

關於proto writeDelimitedTo方法

在整個處理流程中,會非常頻繁的使用的到proto.writeDelimitedTo來傳遞相關proto,簡單理解就是要寫入proto時,寫入總長度,再寫入proto。讀取proto時,先讀取長度,在解析proto。

DataNode連線資料流說明

OpPacket的接收

Op連線第一個包總是來定義Op連線處理那種Op,例如讀塊op,寫塊op。這種包簡單命名為OpPacket。Packet的結構如下,可以根據下圖讀取OpPacket。

1851_1.png

DataTransferProtocol.DATA_TRANSFER_VERSION:short,3.1.1版本預設為28。

OpCode:

1851_2.png

OpProto:定義Op是哪種Op。Op在datatransfer.proto定義,包含OpReadBlockProto,OpWriteBlockProto,OpTransferBlockProto,OpReplaceBlockProto,OpCopyBlockProto,OpBlockChecksumProto,OpRequestShortCircuitAccessProto,ReleaseShortCircuitAccessRequestProto。

接下來的是否回應或者直接發資料,都要根據不同的op來處理,後續介紹了write和read。

WriteBlock

當接收完OpPacket以後,需要寫入一個BlockOpResponseProto應答。

1851_3.png

當客戶端接受BlockOpResponseProto應答後,就會傳送資料包,資料包的格式如下

1851_4.png

PktLen:資料包長度,不同於字面意思,這個數值並不是包的總長度,而是4(pktLen所佔位元組數)+chunkchecksums位元組數+chunkdatas位元組數。
HeadLen:short,PacketHeaderProto的長度。不同於writeDelimitedTo,這邊使用的proto.getSerializedSize。
PktHeadProto:PacketHeaderProto.writeTo。
Chunkchecksums:chunk校驗資料。
ChunkData:實際資料。
DataNode接受到資料以後,完成checksum後就把Status.success放入Responder的處理佇列。Responder最終會返回PipelineAckProto(PipelineAckProto.writeDelimitedTo)給客戶端。

ReadBlock

當接收完OpPacket以後,需要寫入一個BlockOpResponseProto應答。

1851_5.png

寫完應答以後,立馬會傳送Block的資料包,資料包的結果如下:

1851_6.png

PktLen:資料包長度,不同於字面意思,這個數值並不是包的總長度,而是4(pktLen所佔位元組數)+chunkchecksums位元組數+chunkdatas位元組數。
HeadLen:short,PacketHeaderProto的長度。不同於writeDelimitedTo,這邊使用的proto.getSerializedSize。
PktHeadProto:PacketHeaderProto.writeTo。
Chunkchecksums:chunk校驗資料。
ChunkData:實際資料。
資料會被分成多個資料包傳送,傳送完最後一個資料包以後,會傳送一個空包(沒有資料只有header),空包的PacketHeaderProto會有LastPackctInBlock的標記。空包傳送完成後,會接受一個ClientReadStatusProto的包(客戶端使用ClientReadStatusProto.writeDelimitedTo寫入)。

TransferBlock、ReplaceBlock未分析。

資料流中的sasl

Hadoop使用dfs.data.transfer.protection引數來保證資料流的安全。dfs.data.transfer.protection有三種模式authentication,integrity,privacy,分別對於sasl qop中的auth,auth-int,auth-conf。Auth:流建立需要握手,握手成功以後,後續流就是正常使用。
Auth-int:流握手+後續流都需要透過sasl的wrap unwarp加密解密。
Auth-conf:流握手+後續流都需要透過協商的演算法來資料加密解密。

Sasl握手:
Sasl的mech為DIGEST-MD5,serviceName為0,protocol(c中的username)為hdfs。透過此資訊可以建立saslclient,saslserver。DIGEST-MD5的callback的本質上就是驗證使用者名稱密碼。資料流的使用者密碼來源與blocktoken。
關於sasl中協商的包結構為DataTransferEncryptorMessageProto,寫入使用writeDelimitedTo。

message DataTransferEncryptorMessageProto {
  enum DataTransferEncryptorStatus {
    SUCCESS = 0;
    ERROR_UNKNOWN_KEY = 1;
    ERROR = 2;
  }
  required DataTransferEncryptorStatus status = 1;
  optional bytes payload = 2;
  optional string message = 3;
  repeated CipherOptionProto cipherOption = 4;
}

Payload就是token,message只有status為error才使用,為errmsg。Server發生異常都會傳送錯誤,並關閉這個流。

流程圖:

1851_7.png

  1. client傳送sasl_Version,為4byte

SASL_TRANSFER_MAGIC_NUMBER = 0xDEADBEEF;server接收並驗證。

  1. client傳送第一個saslMessage,Status為success,payload為byte[0]。

  2. Server就收到包以後使用saslserver.evaluateResponse(c中為gsasl_setup)來處理payload。

Server傳送應答saslMessage,Status為success,payload為算出來的token。

  1. client接收到包以後,使用saslclient.evaluateChallenge(c中為gsasl_setup)來出來payload。

client傳送第二個saslMessage,Status為success,payload為算出來的token。

  1. Server就收到包以後使用saslserver.evaluateResponse(c中為gsasl_setup)來處理payload。

這時候如果payload沒問題,saslserver會complete。Server傳送應答saslMessage,Status為success,payload為算出來的token。

  1. client接收到包以後,使用saslclient.evaluateChallenge(c中為gsasl_setup)來出來payload。

這時候如果payload沒問題,saslclient會complete。

獨立站原文

相關文章