本文主要闡述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。
DataTransferProtocol.DATA_TRANSFER_VERSION:short,3.1.1版本預設為28。
OpCode:
OpProto:定義Op是哪種Op。Op在datatransfer.proto定義,包含OpReadBlockProto,OpWriteBlockProto,OpTransferBlockProto,OpReplaceBlockProto,OpCopyBlockProto,OpBlockChecksumProto,OpRequestShortCircuitAccessProto,ReleaseShortCircuitAccessRequestProto。
接下來的是否回應或者直接發資料,都要根據不同的op來處理,後續介紹了write和read。
WriteBlock
當接收完OpPacket以後,需要寫入一個BlockOpResponseProto應答。
當客戶端接受BlockOpResponseProto應答後,就會傳送資料包,資料包的格式如下
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應答。
寫完應答以後,立馬會傳送Block的資料包,資料包的結果如下:
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發生異常都會傳送錯誤,並關閉這個流。
流程圖:
- client傳送sasl_Version,為4byte
SASL_TRANSFER_MAGIC_NUMBER = 0xDEADBEEF;server接收並驗證。
-
client傳送第一個saslMessage,Status為success,payload為byte[0]。
-
Server就收到包以後使用saslserver.evaluateResponse(c中為gsasl_setup)來處理payload。
Server傳送應答saslMessage,Status為success,payload為算出來的token。
- client接收到包以後,使用saslclient.evaluateChallenge(c中為gsasl_setup)來出來payload。
client傳送第二個saslMessage,Status為success,payload為算出來的token。
- Server就收到包以後使用saslserver.evaluateResponse(c中為gsasl_setup)來處理payload。
這時候如果payload沒問題,saslserver會complete。Server傳送應答saslMessage,Status為success,payload為算出來的token。
- client接收到包以後,使用saslclient.evaluateChallenge(c中為gsasl_setup)來出來payload。
這時候如果payload沒問題,saslclient會complete。
獨立站原文