HDFS主要流程

HDFS的幾個典型的流程:客戶端讀HDFS文件流程、客戶端寫HDFS文件流程、客戶端追加寫HDFS文件流程、數據節點與名字節點交互流程以及HDFS HA切換流程等。node

1、客戶端讀HDFS文件流程
  1. 打開HDFS文件:HDFS客戶端首先調用DistributedFileSystem.open()方法打開HDFS文件,這個方法在底層會調用ClientProtocol.open()方法,該方法會返回一個HdfsDataInputStream對象用於讀取數據塊。HdfsDataInputStream實際上是一個DFSInputStream的裝飾類,真正進行數據塊讀取操做的是DFSInputStream對象。
  2. 從Namenode獲取Datanode地址:在DFSInputStream的構造方法中,會調用ClientProtocol.getBlockLocations()方法向名字節點獲取該HDFS文件起始位置數據塊的位置信息。Namenode返回的數據塊的存儲位置是按照與客戶端的距離遠近排序的,因此DFSInputStream能夠選擇一個最優的Datanode節點,而後與這個節點創建數據鏈接讀取數據塊。
  3. 鏈接到Datanode讀取數據塊:HDFS客戶端經過調用DFSInputStream.read()方法從這個最優的Datanode讀取數據塊,數據會以數據包(packet)爲單位從數據節點經過流式接口傳送到客戶端。當達到一個數據塊的末尾時,DFSInputStream就會再次調用ClientProtocol.getBlockLocations()獲取文件下一個數據塊的位置信息,並創建和這個新的數據塊的最優節點之間的鏈接,而後HDFS客戶端就能夠繼續讀取數據塊了。
  4. 關閉輸入流:當客戶端成功完成文件讀取後,會經過HdfsDataInputStream.close()方法關閉輸入流。

流程圖以下:緩存

QQ圖片20200916122252.png

客戶端讀取數據塊時,頗有可能存儲這個數據塊的數據節點出現異常,也就是沒法讀取數據。出現這種狀況時,DFSInputStream會切換到另外一個保存了這個數據塊副本的數據節點而後讀取數據。同時須要注意的是,數據塊的應答包中不只包含了數據,還包含了校驗值。HDFS客戶端接收到數據應答包時,會對數據進行校驗,若是出現校驗錯誤,也就是數據節點上的這個數據塊副本出現了損壞,HDFS客戶端就會經過ClientProtocol.reportBadBlocks()向Namenode彙報這個損壞的數據塊副本,同時DFSInputStream會嘗試從其餘的數據節點讀取這個數據塊。spa

2、客戶端寫HDFS文件流程
  1. 建立文件: HDFS客戶端寫-一個 新的文件時,會首先調用DistributedFileSystem.create()方法在HDFS文件系統中建立一個新的空文件。這個方法在底層會經過調用ClientProtocol.create()方法通知Namenode執行對應的操做, Namenode會首先在文件系統目錄樹中的指定路徑下添加一個新的文件,而後將建立新文件的操做記錄到editlog中。完成ClientProtocol.create()調用後, DistributedFileSystem.create()方法就會返回一個HdfsDataOutputStream對象,這個對象在底層包裝了一個DFSOutputStream對象,真正執行寫數據操做的實際上是DFSOutputStream對象。
  2. 創建數據流管道:獲取了DFSOutputStream對象後,HDFS客戶端就能夠調用 DFSOutputStream.write()方法來寫數據了。因爲DistributedFileSystem.create()方法只是在文件系統目錄樹中建立了一個空文件,並無申請任何數據塊,因此DFSOutputStream會首先調用ClientProtocol.addBlock()向Namenode申請一個新的空數據塊,addBlock()方法會返回一個LocatedBlock對象,這個對象保存了存儲這個數據塊的全部數據節點的位置信息。得到了數據流管道中全部數據節點的信息後,DFSOutputStream就能夠創建數據流管道寫數據塊了。
  3. 經過數據流管道寫入數據: 成功地創建數據流管道後,HDFS客戶端就能夠向數據流管道寫數據了。寫入DFSOutputStream中的數據會先被緩存在數據流中,以後這些數據會被切分紅一個個數據包(packet)經過數據流管道發送到全部數據節點。經過數據流管道依次寫入數據節點的本地存儲。每一個數據包都有個確認包(ack),確認包會逆序經過數據流管道回到輸出流。輸出流在確認了全部數據節點已經寫入這個數據包以後,就會從對應的緩存隊列刪除這個數據包。當客戶端寫滿一個數據塊以後,會調用addBlock()申請一個新的數據塊,而後循環執行上述操做。
  4. 關閉輸入流並提交文件: 當HDFS客戶端完成了整個文件中全部數據塊的寫操做以後,就能夠調用close()方法關閉輸出流,並調用ClientProtocol.complete()方法通知Namenode提交這個文件中的全部數據塊,也就完成了整個文件的寫入流程。

流程圖以下:
image.png對象

對於Datanode,當 Datanode成功地接受一個新的數據塊時,Datanode會經過
DatanodeProtocol.blockReceivedAndDeleted()方法向Namenode彙報,Namenode會更新內存中的數據塊與數據節點的對應關係。blog

若是客戶端在寫文件時,數據流管道中的數據節點出現故障,則輸出流會進行以下操做來進行故障恢復。排序

  1. 輸出流中緩存的沒有確認的數據包會從新加入發送隊列,這種機制確保了數據節點出現故障時不會丟失任何數據,全部的數據都是通過確認的。輸出流會經過調用ClientProtocol.updateBlockForPipeline()方法爲數據塊申請一個新的時間戳,而後使用這個新的時間戳從新創建數據流管道。這種機制保證了故障Datanode上的數據塊的時間戳會過時,而後在故障恢復以後,因爲數據塊的時間戳與Namenode元數據中的不匹配而被刪除,保證了集羣中全部數據塊的正確性。
  2. 故障數據節點會從輸入流管道中刪除,而後輸出流會經過調用ClientProtocol.getAdditionalDatanode()方法通知Namenode分配新的數據節點到數據流管道中。接下來輸出流會將新分配的Datanode添加到數據流管道中,並使用新的時間戳從新創建數據流管道。因爲新添加的數據節點上並無存儲這個新的數據塊,這時HDFS客戶端會經過DataTransferProtocol通知數據流管道中的一個Datanode複製這個數據塊到新的Datanode上.
  3. 數據流管道從新創建以後,輸出流會調用ClientProtocol.updatePipeline()更新Namenode中的元數據。至此,一個完整的故障恢復流程就完成了,客戶端能夠正常完成後續的寫操做了。
3、Datanode啓動、心跳以及執行名字節點指令流程

Datanode啓動後與 Namenode 的交互主要包括三個部分:①握手;②註冊;③塊彙報以 及緩存彙報。接口

  1. Datanode啓動時會首先經過DatanodeProtocol.versionRequest()獲取Namenode的版本號以及存儲信息等,而後Datanode會對Namenode的當前軟件版本號和Datanode的當前軟件、版本號進行比較,確保它們是一致的。
  2. 成功地完成握手操做後,Datanode會經過DatanodeProtocol.register()方法向Namenode註冊。Namenode接收到註冊請求後,會判斷當前Datanode的配置是否屬於這個集羣,它們之間的版本號是否一致。
  3. 註冊成功以後,Datanode就須要將本地存儲的全部數據塊以及緩存的數據塊上報到Namenode,Namenode會利用這些信息從新創建內存中數據塊與Datanode之間的對應關係。

至此,Datanode 就完成了啓動的全部操做,以後就能夠正常對外服務了。隊列

Datanode成功啓動以後,須要按期向Namenode發送心跳,讓Namenode知道當前Datanode 處於活動狀態可以對外服務。Namenode 會在Datanode 的心跳響應中攜帶名字節點指令,指導Datanode進行數據塊的複製、刪除以及恢復等操做。圖片

當Datanode成功地添加了一個新的數據塊或者刪除了-一個已有的數據塊時,須要經過 DatanodeProtocol.blockReceivedAndDeleted(方法向Namenode彙報。Namenode接收到這個匯 報以後,會更新Namenode內存中數據塊與數據節點之間的對應關係。ip

相關文章
相關標籤/搜索