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

瘦風發表於2021-03-01

1 - HDFS 檔案的寫入

1.1 寫入過程

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

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 讀取過程

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

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://www.cnblogs.com/shoufeng)

感謝閱讀,公眾號 「瘦風的南牆」 ,手機端閱讀更佳,還有其他福利和心得輸出,歡迎掃碼關注?

本文版權歸博主所有,歡迎轉載,但 [必須在頁面明顯位置標明原文連結],否則博主保留追究相關人士法律責任的權利。

相關文章