1. 程式人生 > >HDFS 03 - 你能說說 HDFS 的寫入和讀取過程嗎?

HDFS 03 - 你能說說 HDFS 的寫入和讀取過程嗎?

[TOC] # 1 - HDFS 檔案的寫入 ## 1.1 寫入過程 1、Client 發起檔案上傳請求,通過 RPC 與 NameNode 建立連線,NameNode 檢查 Client 是否有相應許可權,以及目標檔案是否已存在、父目錄是否存在,向 Client 返回是否可以上傳; 2、Client 從 NameNode 中獲取第一個 block 的傳輸目的地,也就是應該傳輸到哪些 DataNode 上; 3、NameNode 根據配置檔案中指定的備份數量及機架感知原理進行檔案分配,返回可用的 DataNode 的地址,假設分別是 A、B、C; > 機架感知:Hadoop 在設計時考慮到資料儲存的安全與高效,資料檔案在 HDFS 上預設存放三份副本。 >
> 副本的儲存策略為:客戶端所在 DataNode 一份,同機架內其它某一節點上一份,不同機架的某一節點上一份。 4、Client 先向 DataNode A 上傳資料(也是一個 RPC 呼叫,建立 pipeline ),A 收到請求會繼續呼叫 B,然後 B 呼叫 C,建立完成所有的 pipeline 之後,逐級返回 Client; 5、Client 開始向 DataNode A 上傳第一個 block,以 packet 為單位(預設是64K),A 收到一個 packet 就會傳給 B,B 傳給 C,A 每傳一個 packet 會放入一個 ack 佇列等待應答; 6、資料被分割成一個個的 packet 資料包在 pipeline 上依次傳輸,在 pipeline 反方向上逐個傳送 ack(操作是否成功的應答),最終由 pipeline 中第一個 DataNode 節點 A 將 pipelineack 傳送給 Client; 7、當一個 block 傳輸完成後,Client 再次請求 NameNode 上傳第二個 block ,繼續上述 (4) - (7) 步驟。 ## 1.2 寫入異常時的處理 當資料寫入失敗時,HDFS 會作出以下反應: >
**首先管道會被關閉**,任何在確認通知佇列中的檔案包都會被新增到資料佇列的前端,以確保故障節點下游的 DataNode 不會漏掉任何一個數據包。 > > 為儲存在另一個正常的 DataNode 的當前資料塊指定一個新的標識,並將標識傳送給 NameNode,以便 **故障 DataNode 在恢復後可以刪除儲存的部分資料塊**。 > > 刪除故障 DataNode 的 pipeline 連線,基於兩個正常的 DataNode 構建新的 pipeline,剩餘的資料塊寫入新的 pipeline 中。 **NameNode 在注意到副本個數不足時,會在其他 DataNode 上建立一個新的副本**。後續的資料塊就能正常的接受處理。 ## 1.3 寫入的一致性 - 新建一個檔案後,HDFS 的名稱空間中立即可見; - 寫入檔案的內容不保證立即可見(即使資料流已經呼叫 `flush()` 方法重新整理並存儲); - 當前正在寫入的塊對其他 Reader 不可見; - 呼叫 `hflush()` 方法後,資料被寫入 DataNode 的記憶體中,可保證對所有 Reader 可見; - 呼叫 `hsync()` 方法後,資料就會被寫到磁碟上; - 如果沒有呼叫 `hflush()` 或 `hsync()`,客戶端在故障的情況下可能丟失正在寫入的資料塊。 # 2 - HDFS 檔案的讀取 ## 2.1 讀取過程
1、Client 向 NameNode 發起 RPC 請求,來確定請求檔案 block 所在的位置; 2、NameNode 會視情況返回檔案的部分或者全部 block 列表:對每個 block,NameNode 都會返回含有該 block 副本的 DataNode 地址 —— 按照叢集拓撲結構得出 DataNode 與客戶端的距離,然後進行排序,排序規則是: > 網路拓撲結構中距離 Client 近的靠前 —— 網路拓撲需要根據資料中心、機架、資料節點等因素手動設定; > > 心跳機制中超時彙報的 DataNnode 狀態為 STALE 的排靠後。 3、Client 選取排序靠前的 DataNode 來讀取 block,如果客戶端本身就是 DataNode,就會從本地直接獲取資料(短路讀取特性); 4、底層本質是建立 Socket Stream(FSDataInputStream),重複呼叫父類 DataInputStream 的 read 方法,直到這個 block 上的資料讀取完畢; 5、當讀完列表的 block 後,若檔案讀取還沒有結束,客戶端會繼續向 NameNode 獲取下一批的 block 列表; > **DataInputStream#read() 方法是並行讀取 block 資訊,仍然是以 packet 為單位(預設是64K)在 pipeline 上依次傳輸;** 6、讀取完所有的 block 後,客戶端會將它們合併成一個完整的檔案。 **【注意】NameNode 只是返回 Client 請求的 block 的 DataNode 地址,並不會返回 block 的具體資料。** ## 2.2 讀取異常時的處理 1)如果客戶端和所連線的 DataNode 在讀取資料時出現故障,那客戶端就會去嘗試連線儲存這個 block 的下一個最近的 DataNode,同時它會 **記錄這個發生故障的 DataNode**,以免後面再次連線該節點。 2)客戶端每讀完一個 block 都會進行 checksum 驗證,如果從某個 DataNode 上讀取到的 block 是損壞的,客戶端會通知 NameNode 更新該 block 的相關資訊,然後從下一個擁有該 block 副本的 DataNode 繼續讀取檔案。 > # 版權宣告 > > 作者:[瘦風(https://healchow.com)](https://healchow.com) > > 出處:[部落格園-瘦風的南牆(https://www.cnblogs.com/shoufeng)](https://www.cnblogs.com/shoufeng) > > **感謝閱讀,公眾號 [「瘦風的南牆」](https://mp.weixin.qq.com/s/EPUA_78SNmVqoCB4CcrJag) ,手機端閱讀更佳,還有其他福利和心得輸出,歡迎掃碼關注