檔案讀取流程
<a target="_blank" href="http://blog.51cto.com/attachment/201309/090008850.png"></a>
1) 用戶端首先要調用FileSystem對象的靜态方法open()方法來打開一個希望讀取檔案的路徑,在HDFS中檔案的對象為Path對象(與Java中的File相對應)。
2) FileSystem對象就是一個DistributedFileSystem對象,通過利用RPC來調用NameNode節點,(NameNode節點存儲着整個檔案系統目錄、檔案以及檔案所在塊的位置資訊),來确定我們需要打開的檔案所有資料塊的存儲位置。檔案在被存入HDFS中,會被劃分為多個資料塊存儲的,對于每一個資料塊,namenode都會傳回存有該資料塊副本的datanode位址。資料塊副本的datanode位址會根據與用戶端的距離來排序。DistributedFileSystem傳回一個FSDataInputStream對象給client用來讀取資料。FSDataInputStream封裝了DFSInputStream對象,該對象用于管理NameNode和DataNode的I/O
3) 用戶端利用該FSDataInputStream對象的輸入流調用read()方法。輸入流會首先讀取距離用戶端最近的datanode,反複讀取,直到将該datanode資料讀取完後,然後就會FSDataInputStream關閉與該datanode的連接配接,然後繼續尋找下一個datanode節點。
4) 用戶端讀取檔案,資料塊都是按照DFSInputStream與datanode連接配接的距離順序讀取,也會詢問namenode下一批資料塊的datanode位置,整個檔案讀取完後,就會馬上調用FSDataInputStream的close()方法。
讀取中的失敗錯誤處理:當讀取資料時,DFSInputStream與datanode通信失敗,則會讀取這個塊的最接近該datanode的節點來讀取資料,并且以後不會反複讀取該失敗節點。
namenode僅僅提供給用戶端檢索檔案的作用,告知用戶端每個塊最佳datanode(利用排序),它僅僅響應資料塊位置的請求,而無需響應資料請求。具體的資料流都是由用戶端與datanode直接通信的。
檔案寫入流程
<a target="_blank" href="http://blog.51cto.com/attachment/201309/092137494.png"></a>
1). client通過調用DistributedFileSystem的create()方法來建立檔案。
2). DistributedFileSystem通過RPC調用NameNode在檔案系統的名字空間裡建立一個新檔案,名稱節點首先确定檔案原來不存在,并且用戶端有建立檔案的權限,然後建立新檔案,這個時候還沒有任何塊的資訊。DistributedFileSystem傳回FSDataOutputStream給client。FSDataOutputStream封裝了一個DFSOutputStream對象,該對象負責處理datanode和namenode之間的通訊。
3). 當Client開始寫資料的時候,DFSOutputStream把檔案的資料分成一個個資料包,并寫入内部對列DataQueue。DataQueue是由DataStreamer負責讀取,DataStreamer通知NameNode配置設定DataNode,用來存儲資料塊(每塊預設複制3塊),配置設定的DataNode清單形成一個管道(pipeline)。在上圖中管道由三個datanode組成,這三個datanode的選擇有一定的副本放置政策。
4). DataStreamer将資料塊流式傳輸到pipeline中的第一個DataNode,第一個DataNode存儲資料塊并将資料塊發送給pipeline中的第二個DataNode,同樣的,第二個DataNode存儲資料塊并将資料塊發送給pipeline中的第三個DataNode。
5). 同時,DFSOutputStream也管理ackqueue(确認隊列),ackqueue裡存儲着等待datanode識别的資料塊,隻有當管道裡所有datanode都傳回寫入成功,這個資料塊才算寫成功,才會從ackqueue中删除,開始寫下一個資料塊。
如果某個datanode發生故障,寫失敗了,則會執行如下步驟,但是這些對client是透明的。
1) 管道關閉。
2)正常的datanode上的目前block會有一個新ID,并将該ID傳送給namenode,以便失敗的datanode在恢複後可以删除那個不完整的block。
3) 失敗的datanode會被移出管道,餘下的資料塊繼續寫入管道的其他兩個正常的datanode。
4) namenode會标記這個block的副本個數少于指定值。block的副本會稍後在另一個datanode建立。
5)有些時候多個datanode會失敗,但非常少見。隻要dfs.replication.min(預設是1)個datanode成功了,整個寫入過程就算成功。缺少的副本會在叢集中異步的複制,直到達到正常的副本數。
6. 當client完成了所有block的寫入後,調用FSDataOutputStream的close()方法關閉檔案。
7. FSDataOutputStream通知namenode寫檔案結束。
檔案寫入中的副本政策:
1) Hadoop預設副本政策是将第一個複本放在運作用戶端的節點上,即上傳檔案或者寫入檔案所在的datanode節點上。如果用戶端不在叢集中,則就随機選擇一個節點。
2) 第二個複本放在與第一個複本不同且随機的另外的機架上。
3) 第三個複本與第二個複本放在相同的機架上。
本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1287660