大文件會被分割成多個block進行存儲,block大小默認爲64MB。每個block會在多個datanode上存儲多份副本,默認是3份。node
HDFS是按照Master和Slave的結構進行設計的。分爲NameNode、SecondaryNameNode、DataNode這幾個角色。網絡
namenode:併發
namenode是Master節點,負責管理文件目錄、文件和block的對應關係以及block和datanode的對應關係還有datanode的副本信息,協調客戶端對文件的訪問,記錄命名空間內的改動或自己屬性的改變;使用事務日誌記錄HDFS元數據的變化,使用映像文件存儲文件系統的命名空間,包括文件映射文件屬性。異步
SecondaryNameNode:分佈式
是NameNode的冷備份,負責定時默認1小時,從namenode上,獲取fsimage和edits來進行合併,而後再發送給namenode。減小namenode的工做量。oop
DataNode:佈局
datanode是Slave節點負責存儲client發來的數據塊block,固然大部分容錯機制都是在datanode上實現的,一次寫入屢次讀取不修改。this
讀取流程:spa
客戶端要訪問HDFS中的一個文件,首先從namenode獲取組成這個文件的數據塊位置列表,根據列表知道數據塊的datanode,訪問datanode獲取數據。(namenode不參與實際數據傳輸)設計
1)客戶端經過調用FileSystem對象的open()來讀取但願打開的文件。對於HDFS來講,這個對象是分佈式文件系統的一個實例。
2)DistributedFileSystem經過RPC來調用namenode,以肯定文件的開頭部分的塊位置。對於每一塊,namenode返回具備該塊副本的datanode地址。此外,這些datanode根據他們與client的距離來排序(根據網絡集羣的拓撲)。若是該client自己就是一個datanode,便從本地datanode中讀取。DistributedFileSystem返回一個FSDataInputStream對象給client讀取數據,FSDataInputStream轉而包裝了一個DFSInputStream對象。
3)接着client對這個輸入流調用read()。存儲着文件開頭部分的塊的數據節點的地址DFSInputStream隨即與這些塊最近的datanode相鏈接。
4)經過在數據流中反覆調用read(),數據會從datanode返回client。
5)到達塊的末端時,DFSInputStream會關閉與datanode間的聯繫,而後爲下一個塊找到最佳的datanode。client端只須要讀取一個連續的流,這些對於client來講都是透明的。
6)在讀取的時候,若是client與datanode通訊時遇到一個錯誤,那麼它就會去嘗試對這個塊來講下一個最近的塊。它也會記住那個故障節點的datanode,以保證不會再對以後的塊進行徒勞無益的嘗試。client也會確認datanode發來的數據的校驗和。若是發現一個損壞的塊,它就會在client試圖從別的datanode中讀取一個塊的副本以前報告給namenode。
7)這個設計的一個重點是,client直接聯繫datanode去檢索數據,並被namenode指引到塊中最好的datanode。由於數據流在此集羣中是在全部datanode分散進行的。
因此這種設計能使HDFS可擴展到最大的併發client數量。同時,namenode只不過提供塊的位置請求(存儲在內存中,十分高效),不是提供數據。不然若是客戶端數量增加,namenode就會快速成爲一個「瓶頸」。
客戶端請求namenode建立新文件,客戶端將數據寫入DFSOutputStream,創建pipeline依次將目標數據塊寫入各個datanode,創建多個副本。
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發生故障,首先管線被關閉,確認隊列中的任何包都會被添加回數據隊列的前面,以確保故障節點下游的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組成。
2)namenode查看Metadata信息,返回fileA的block的位置。
block1:host2,host1,host3
block2:host7,host8,host4
3)block的位置是有前後順序的,先讀block1,再讀block2。並且block1去host2上讀取;而後block2,去host7上讀取;
列出HDFS下全部文件夾:
./bin/hadoop fs -ls
列出HDFS下input目錄下文件:
./bin/hadoop fs -ls input
上傳文件到指定目錄:這裏上傳/home/data/words文件 到input目錄。
./bin/hadoop fs -put /home/data/words input
查看上傳結果
從HDFS中複製文件到本地文件夾:複製HDFS中input/words文件到 hadoop目錄下tmp文件夾
./bin/hadoop fs -get input/words tmp/
刪除HDFS中文件:將HDFS中文件input/README.txt刪除
./bin/hadoop fs -rmr input/README.txt
查看HDFS基本統計信息:
[root@hadoop hadoop-2.7.1]# ./bin/hadoop dfsadmin -report DEPRECATED: Use of this script to execute hdfs command is deprecated. Instead use the hdfs command for it. Configured Capacity: 18779398144 (17.49 GB) Present Capacity: 9945313280 (9.26 GB) DFS Remaining: 9944788992 (9.26 GB) DFS Used: 524288 (512 KB) DFS Used%: 0.01% Under replicated blocks: 0 Blocks with corrupt replicas: 0 Missing blocks: 0 Missing blocks (with replication factor 1): 0 ------------------------------------------------- Live datanodes (1): Name: 192.168.1.113:50010 (hadoop) Hostname: hadoop Decommission Status : Normal Configured Capacity: 18779398144 (17.49 GB) DFS Used: 524288 (512 KB) Non DFS Used: 8834084864 (8.23 GB) DFS Remaining: 9944788992 (9.26 GB) DFS Used%: 0.00% DFS Remaining%: 52.96% Configured Cache Capacity: 0 (0 B) Cache Used: 0 (0 B) Cache Remaining: 0 (0 B) Cache Used%: 100.00% Cache Remaining%: 0.00% Xceivers: 1 Last contact: Sun Jan 21 00:48:13 PST 2018