HDFS詳解(2)——HDFS中的讀寫數據流


1.文件的讀取

在客戶端執行讀取操作時,客戶端和HDFS交互過程以及NameNode和各DataNode之間的數據流是怎樣的?下面將圍繞圖1進行具體講解。

          圖 1 客戶端從HDFS中讀取數據 

1)客戶端通過調用FileSystem對象中的open()函數來讀取它做需要的數據。FileSystem是HDFS中DistributedFileSystem的一個實例。

2)DistributedFileSystem會通過RPC協議調用NameNode來確定請求文件塊所在的位置。

這里需要注意的是,NameNode只會返回所調用文件中開始的幾個塊而不是全部返回。對於每個返回的塊,都包含塊所在的DataNode地址。隨后,這些返回的DataNode會按照Hadoop定義的集群拓撲結構得出客戶端的距離,然后再進行排序。如果客戶端本身就是一個DataNode,那么它就從本地讀取文件。其次,DistributedFileSystem會向客戶端返回一個支持文件定位的輸入流對象FSDataInputStream,用於給客戶端讀取數據。FSDataInputStream包含一個DFSInputStream對象,這個對象用來管理DataNode和NameNode之間的IO。

3)當以上步驟完成時,客戶端便會在這個輸入流上調用read()函數。

4)DFSInputStream對象中包含文件開始部分數據塊所在的DataNode地址,首先它會連接文件第一個塊最近的DataNode。隨后,在數據流中重復調用read()函數,直到這個塊完全讀完為止。

5)當第一個塊讀取完畢時,DFSInputStream會關閉連接,並查找存儲下一個數據庫距離客戶端最近的DataNode。以上這些步驟對於客戶端來說都是透明的。

6)客戶端按照DFSInputStream打開和DataNode連接返回的數據流的順序讀取該塊,它也會調用NameNode來檢索下一組塊所在的DataNode的位置信息。當完成所有文件的讀取時,客戶端則會在DFSInputStream中調用close()函數。

那么如果客戶端正在讀取數據時節點出現故障HDFS會怎么辦呢?目前HDFS是這樣處理的:如果客戶端和所連接的DataNode在讀取時出現故障,那么它就會去嘗試連接存儲這個塊的下一個最近的DataNode,同時它會記錄這個節點的故障,以免后面再次連接該節點。客戶端還會驗證從DataNode傳送過來的數據校驗和。如果發現一個損壞塊,那么客戶端將再嘗試從別的DataNode讀取數據塊,向NameNode報告這個信息,NameNode也會更新保存的文件信息。

這里關注的一個設計要點是,客戶端通過NameNode引導獲取最合適的DataNode地址,然后直接連接DataNode讀取數據。這樣設計的好處在於,可以使HDFS擴展到更大規模的客戶端並行處理,這是因為數據的流動是在所有DataNode之間分散進行的;同時NameNode的壓力也變小了,使得NameNode只用提供請求塊所在的位置信息就可以了,而不用通過它提供數據,這樣就避免了NameNode隨着客戶端數量的增長而成為系統瓶頸。

2.文件的寫入

那HDFS中文件的寫入過程又是怎樣的呢?以下將圍繞圖2來進行介紹。

           圖2 客戶端在HDFS中寫入數據

1)客戶端通過調用DistributedFileSystem對象中的create()函數創建一個文件。DistributedFileSystem通過RPC調用在NameNode的文件系統命名空間中創建一個新文件,此時還沒有相關的DataNode與之相關。

2)NameNode會通過多種驗證保證新的文件不存在文件系統中,並且確保請求客戶端擁有創建文件的權限。當所有驗證通過時,NameNode會創建一個新文件的記錄,如果創建失敗,則拋出一個IOException異常;如果成功,則DistributedFileSystem返回一個FSDataOutputStream給客戶端用來寫入數據。這里FSDataOutputStream和讀取數據時的FSDataOutputStream一樣都包含一個數據流對象DFSOutputStream,客戶端將使用它來處理和DataNode及NameNode之間的通信。

3),4)當客戶端寫入數據時,DFSOutputStream會將文件分割成包,然后放入一個內部隊列,我們稱為“數據隊列”。DataStreamer會將這些小的文件包放入數據流中,DataStreamer的作用是請求NameNode為新的文件包分配合適的DataNode存放副本。返回的DataNode列表形成一個“管道”,假設這里的副本數是3,那么這個管道中就會有3個DataNode。DataStreamer將文件包以流的方式傳送給隊列中的第一個DataNode。第一個DataNode會存儲這個包,然后將它推送到第二個DataNode中,隨后照這樣進行,直到管道中的最后一個DataNode。

5)DFSOutputStream同時也會保存一個包的內部隊列,用來等待管道中的DataNode返回確認信息,這個隊列被稱為確認隊列(ask queue)。只有當所有的管道中的DataNode都返回了寫入成功的信息文件包,才會從確認隊列中刪除。

當然HDFS會考慮寫入失敗的情況,當數據寫入節點失敗時,HDFS會作出以下反應.首先管道會被關閉,任何在確認通知隊列中的文件包都會被添加到數據隊列的前端,這樣管道中失敗的DataNode都不會丟失數據。當前存放於正常工作DataNode之上的文件塊會被賦予一個新的身份,並且和NameNode進行關聯,這樣,如果失敗的DataNode過段時間從故障中恢復過來,其中的部分數據塊就會被刪除。然后管道會把失敗的DataNode刪除,文件會繼續被寫到管道中的另外兩個DataNode中。最后NameNode會注意到現在的文件塊副本數沒有到達配置屬性要求,會在另外的DataNode上重新安排創建一個副本。隨后的文件會正常執行寫入操作。

當然,在文件塊寫入期間,多個DataNode同時出現故障的可能性存在,但是很小。只要dfs.replication.min的屬性值(默認為1)成功寫入,這個文件塊就會被異步復制到其他DataNode中,直到滿足dfs.replictaion屬性值(默認值為3)。

6)客戶端成功完成數據寫入的操作后,就會調用close()函數關閉數據流。這步操作會在連接NameNode確認文件寫入完全之前將所有剩下的文件包放入DataNode管道,等待通知確認信息。NameNode會知道哪些塊組成一個文件(通過DataStreamer獲得塊的位置信息),這樣NameNode只要在返回成功標志前等待塊被最小量(dfs.replication.min)復制即可。

 參考資料:Hadoop實戰 第2版 陸嘉恆著


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM