HDFS的檔案寫入原理,主要包括以下幾個步驟:
1.用戶端通過調用DistributedFileSystem的create方法,建立一個新的檔案。
2.DistributedFileSystem通過RPC(遠端過程調用)調用NameNode,去建立一個沒有blocks關聯的新檔案。建立前,NameNode 會做各種校驗,比如檔案是否存在,用戶端有無權限去建立等。如果校驗通過,NameNode就會記錄下新檔案,否則就會抛出IO異常。
3.前兩步結束後會傳回 FSDataOutputStream 的對象,和讀檔案的時候相似,FSDataOutputStream 被封裝成 DFSOutputStream,DFSOutputStream 可以協調 NameNode和 DataNode。用戶端開始寫資料到DFSOutputStream,DFSOutputStream會把資料切成一個個小packet,然後排成隊列 data queue。
4.DataStreamer 會去處理接受 data queue,它先問詢 NameNode 這個新的 block 最适合存儲的在哪幾個DataNode裡,比如重複數是3,那麼就找到3個最适合的 DataNode,把它們排成一個 pipeline。DataStreamer 把 packet 按隊列輸出到管道的第一個 DataNode 中,第一個 DataNode又把 packet 輸出到第二個 DataNode 中,以此類推。
5.DFSOutputStream 還有一個隊列叫 ack queue,也是由 packet 組成,等待DataNode的收到響應,當pipeline中的所有DataNode都表示已經收到的時候,這時akc queue才會把對應的packet包移除掉。
6.用戶端完成寫資料後,調用close方法關閉寫入流。
7.DataStreamer 把剩餘的包都刷到 pipeline 裡,然後等待 ack 資訊,收到最後一個 ack 後,通知 DataNode 把檔案标示為已完成。

第一,用戶端通過調用DistributedFileSystem對象中的creat()函數建立一個檔案,DistributedFileSystem通過RPC調用在NameNode的檔案系統命名空間中建立一個新檔案,此時還沒有相關的DataNode與之關聯。
第二,NameNode會通過多種驗證保證新的檔案不存在于檔案系統中,并且確定請求用戶端擁有建立檔案的權限。當所有驗證通過時,NameNode會建立一個新檔案的記錄,如果建立失敗,則抛出一個IOExceptinn異常;如果成功,則DistrihutedFiieSystem傳回一個FSDataOutputStream給用戶端用來寫入資料。這裡FSDataOutputStream和讀取資料時的FSDataInputStream一樣都包含一個資料流對象DFSOutputStream,用戶端将使用它來處理與DataNode和NameNode之間的通信。
第三,當用戶端寫入資料時,DFSOutputStream會将檔案分割成包,然後放入一個内部隊列,我們稱為“資料隊列”。DataStreamer會将這些小的檔案包放入資料流中,DataStreamer的作用是請求NameNode為新的檔案包配置設定合适的DataNade存放副本。傳回的DataNode清單形成一個“管道”,假設這裡的副本數是3,那麼這個管道中就會有3個DataNode, DataStreamer将檔案包以流的方式傳送給隊列中的第一個DataNode。第一個DataNDode會存儲這個包,然後将它推送到第二個DataNode中,随後照這樣進行,直到管道中的最後一個DataNode。
第四,DFSOutputStream同時也會儲存一個包的内部隊列,用來等待管道中的DataNode傳回确認資訊,這個隊列被稱為确認隊列〔ack queue)。隻有當所有管道中的DataNode都傳回了寫入成功的傳回資訊檔案包,才會從确認隊列中删除。
當然,HDFS會考慮寫入失敗的情況,當資料寫入節點失敗時,HDFS會做出以下反應。首先管道會被關閉,任何在确認通知隊列中的檔案包都會被添加到資料隊列的前端,這樣管道中失敗的DataNode都不會丢失資料。目前存放在正常工作的DataNode之上的檔案塊會被賦予一個新的身份,井且和NameNode進行關聯,這樣,如果失敗的DataNode過段時間後會從故障中恢複出來。其中的部分資料塊就會被删除。然後,管道會把失敗的DataNode删除,檔案會繼續被寫到管道中的另外兩個DataNode中。最後,NameNode會注意到現在的檔案塊副本數沒有達到配置屬性要求,會在另外的DataNode上重新安排建立一個副本,随後的檔案會正常執行寫入操作。
當然,在檔案塊寫入期間,多個DataNode同時出現故障的可能性存在,但是很小。隻要dfs.replicatinn.min的屬性值(預設為1)成功寫入,這個檔案塊就會被異步複制到叢集的其他 DataNode中,直到滿足dfs. rcplication. min的屬性值(預設為3)。
用戶端成功完成資料寫入的操作後,就會調用6種close()函數關閉資料流。這步操作會在連接配接NameNode确認檔案寫入完全之前将所有剩下的檔案包放入DataNode管道,等待通知确認資訊.NameNode會知道哪些塊組成一個檔案(通過DataStreamer獲得塊位置資訊),這樣NameNode隻要在傳回成功标志前等待塊被最小量(dfs.replication.min )複制即可。
本文轉自大資料躺過的坑部落格園部落格,原文連結:http://www.cnblogs.com/zlslch/p/5080350.html,如需轉載請自行聯系原作者