閱讀目錄(Content)node
前言網絡
其實說到HDFS的存儲原理,無非就是讀操做和寫操做,那接下來咱們詳細的看一下HDFS是怎麼實現讀寫操做的!併發
1)客戶端經過調用FileSystem對象的open()來讀取但願打開的文件。對於HDFS來講,這個對象是分佈式文件系統的一個實例。異步
2)DistributedFileSystem經過RPC來調用namenode,以肯定文件的開頭部分的塊位置。對於每一塊,namenode返回具備該塊副本的datanode地址。分佈式
此外,這些datanode根據他們與client的距離來排序(根據網絡集羣的拓撲)。若是該client自己就是一個datanode,便從本地datanode中讀取。oop
DistributedFileSystem返回一個FSDataInputStream對象給client讀取數據,FSDataInputStream轉而包裝了一個DFSInputStream對象。佈局
3)接着client對這個輸入流調用read()。存儲着文件開頭部分的塊的數據節點的地址DFSInputStream隨即與這些塊最近的datanode相鏈接。spa
4)經過在數據流中反覆調用read(),數據會從datanode返回client。設計
5)到達塊的末端時,DFSInputStream會關閉與datanode間的聯繫,而後爲下一個塊找到最佳的datanode。client端只須要讀取一個連續的流,這些對於client來講都是透明的。3d
6)在讀取的時候,若是client與datanode通訊時遇到一個錯誤,那麼它就會去嘗試對這個塊來講下一個最近的塊。它也會記住那個故障節點的datanode,以保證不會再對以後的塊進行徒勞無益的嘗試。
client也會確認datanode發來的數據的校驗和。若是發現一個損壞的塊,它就會在client試圖從別的datanode中讀取一個塊的副本以前報告給namenode。
7)這個設計的一個重點是,client直接聯繫datanode去檢索數據,並被namenode指引到塊中最好的datanode。由於數據流在此集羣中是在全部datanode分散進行的。
因此這種設計能使HDFS可擴展到最大的併發client數量。同時,namenode只不過提供塊的位置請求(存儲在內存中,十分高效),不是提供數據。不然若是客戶端數量增加,namenode就會快速成爲一個「瓶頸」。
注意:
這裏HdfsDataInputStream是FSDataInputStream的子類,這裏是經過子類建立父類對象。
1)客戶端經過在DistributedFileSystem中調用create()來建立文件。
2)DistributedFileSystem 使用RPC去調用namenode,在文件系統的命名空間創一個新的文件,沒有塊與之相聯繫。
namenode執行各類不一樣的檢查(這個文件存不存在,有沒有權限去寫,能不能存的下這個文件)以確保這個文件不會已經存在,而且在client有能夠建立文件的適當的許可。
若是檢查經過,namenode就會生成一個新的文件記錄;不然,文件建立失敗並向client拋出一個IOException異常。
分佈式文件系統返回一個文件系統數據輸出流,讓client開始寫入數據。就像讀取事件同樣,文件系統數據輸出流控制一個DFSOutputStream,負責處理datanode和namenode之間的通訊。
3)在client寫入數據時,DFSOutputStream將它分紅一個個的包,寫入內部的隊列,成爲數據隊列。數據隊列隨數據流流動,數據流的責任是根據適合的datanode的列表要求這些節點爲副本分配新的塊。
這個數據節點的列表造成一個管線——假設副本數是3,因此有3個節點在管線中。
4)數據流將包分流給管線中第一個的datanode,這個節點會存儲包而且發送給管線中的第二個datanode。一樣地,第二個datanode存儲包而且傳給管線中的第三個數據節點。
5)DFSOutputStream也有一個內部的包隊列來等待datanode收到確認,成爲確認隊列。一個包只有在被管線中全部的節點確認後纔會被移除出確認隊列。若是在有數據寫入期間,datanode發生故障,
則會執行下面的操做,固然這對寫入數據的client而言是透明的。首先管線被關閉,確認隊列中的任何包都會被添加回數據隊列的前面,以確保故障節點下游的datanode不會漏掉任意一個包。
爲存儲在另外一正常datanode的當前數據塊制定一個新的標識,並將該標識傳給namenode,以便故障節點datanode在恢復後能夠刪除存儲的部分數據塊。
從管線中刪除故障數據節點而且把餘下的數據塊寫入管線中的兩個正常的datanode。namenode注意到塊複本量不足時,會在另外一個節點上建立一個新的複本。
後續的數據塊繼續正常接收處理。只要dfs.replication.min的副本(默認是1)被寫入,寫操做就是成功的,而且這個塊會在集羣中被異步複製,直到其知足目標副本數(dfs.replication 默認值爲3)。
6)client完成數據的寫入後,就會在流中調用close()。
7)在向namenode節點發送完消息以前,此方法會將餘下的全部包放入datanode管線並等待確認。
namenode節點已經知道文件由哪些塊組成(經過Data streamer 詢問塊分配),因此它只需在返回成功前等待塊進行最小量的複製。
8)補充說明——複本的佈局:Hadoop的默認佈局策略是在運行客戶端的節點上放第1個複本(若是客戶端運行在集羣以外,就隨機選擇一個節點,不過系統會避免挑選那些存儲太滿或太忙的節點。)
第2個複本放在與第1個複本不一樣且隨機另外選擇的機架的節點上(離架)。第3個複本與第2個複本放在相同的機架,且隨機選擇另外一個節點。其餘複本放在集羣中隨機的節點上,不過系統會盡可能避免相同的機架放太多複本。
前提:
有一個文件FileA,100M大小。Client將FileA寫入到HDFS上。
HDFS按默認配置。
HDFS分佈在三個機架上Rack1,Rack2,Rack3。
步驟:
1) Client將FileA按64M分塊。分紅兩塊,block1和Block2;
2) Client向nameNode發送寫數據請求,如圖藍色虛線①------>。
3) NameNode節點,記錄block信息。並返回可用的DataNode,如粉色虛線②--------->。
Block1: host2,host1,host3
Block2: host7,host8,host4
原理:
NameNode具備RackAware機架感知功能,這個能夠配置。
若client爲DataNode節點,那存儲block時,規則爲:副本1,同client的節點上;副本2,不一樣機架節點上;副本3,同第二個副本機架的另外一個節點上;其餘副本隨機挑選。
若client不爲DataNode節點,那存儲block時,規則爲:副本1,隨機選擇一個節點上;副本2,不一樣副本1,機架上;副本3,同副本2相同的另外一個節點上;其餘副本隨機挑選。
4)client向DataNode發送block1;發送過程是以流式寫入。
流式寫入過程:
第一步:將64M的block1按64k的package劃分;
第二步:而後將第一個package發送給host2;
第三步:host2接收完後,將第一個package發送給host1,同時client想host2發送第二個package;
第四步:host1接收完第一個package後,發送給host3,同時接收host2發來的第二個package。
第五步:以此類推,如圖紅線實線所示,直到將block1發送完畢。
第六步:host2,host1,host3向NameNode,host2向Client發送通知,說「消息發送完了」。如圖粉紅顏色實線所示。
第七步:client收到host2發來的消息後,向namenode發送消息,說我寫完了。這樣就真完成了。如圖黃色粗實線
第八步:發送完block1後,再向host7,host8,host4發送block2,如圖藍色實線所示。
第九步:發送完block2後,host7,host8,host4向NameNode,host7向Client發送通知,如圖淺綠色實線所示。
第十步:client向NameNode發送消息,說我寫完了,如圖黃色粗實線。。。這樣就完畢了。
分析:
經過寫過程,咱們能夠了解到:
1)寫1T文件,咱們須要3T的存儲,3T的網絡流量貸款。
2)在執行讀或寫的過程當中,NameNode和DataNode經過HeartBeat進行保存通訊,肯定DataNode活着。
若是發現DataNode死掉了,就將死掉的DataNode上的數據,放到其餘節點去。讀取時,要讀其餘節點去。
3)掛掉一個節點,不要緊,還有其餘節點能夠備份;甚至,掛掉某一個機架,也不要緊;其餘機架上,也有備份。
讀操做就簡單一些了,如圖所示,client要從datanode上,讀取FileA。而FileA由block1和block2組成。
那麼,讀操做流程爲:
1)client向namenode發送讀請求。
2)namenode查看Metadata信息,返回fileA的block的位置。
block1:host2,host1,host3
block2:host7,host8,host4
3)block的位置是有前後順序的,先讀block1,再讀block2。並且block1去host2上讀取;而後block2,去host7上讀取;
上面例子中,client位於機架外,那麼若是client位於機架內某個DataNode上,例如,client是host6。那麼讀取的時候,遵循的規律是:優選讀取本機架上的數據。
以簡潔易懂的漫畫形式講解HDFS存儲機制與運行原理
如上圖所示,HDFS存儲相關角色與功能以下:
Client:客戶端,系統使用者,調用HDFS API操做文件;與NN交互獲取文件元數據;與DN交互進行數據讀寫。
Namenode:元數據節點,是系統惟一的管理者。負責元數據的管理;與client交互進行提供元數據查詢;分配數據存儲節點等。
Datanode:數據存儲節點,負責數據塊的存儲與冗餘備份;執行數據塊的讀寫操做等。
1)用戶需求
HDFS採用的是「一次寫入屢次讀取」的文件訪問模型。一個文件通過建立、寫入和關閉以後就不須要改變。這一假設簡化了數據一致性問題,而且使高吞吐量的數據訪問成爲可能。
2)先聯繫元數據節點
3)下載數據
數據存儲已經按照客戶端與DataNode節點之間的距離進行了排序,距客戶端越近的DataNode節點被放在最前面,客戶端會優先從本地讀取該數據塊。
1)發送寫數據請求
HDFS中的存儲單元是block。文件一般被分紅64或128M一塊的數據塊進行存儲。與普通文件系統不一樣的是,在HDFS中,若是一個文件大小小於一個數據塊的大小,它是不須要佔用整個數據塊的存儲空間的。
2)文件切分
3)DN分配
4)數據寫入
5)寫入完成
6)角色定位
-END-