HDFS是Hadoop分佈式文件系統,用來分佈式存儲海量數據,並具備高可靠、高性能、可伸縮的能力。java
HDFS屏蔽了分佈式存儲的細節,提供了標準的訪問方式,可以以相似訪問本地文件系統的方式訪問HDFS中的文件。node
以下是HDFS的架構圖:shell
1.namenode 管理元數據數據庫
2.datanode 存儲文件塊apache
3.Block 文件塊,BlockSize 128MBwindows
4.Replication 文件塊的副本安全
5.Rack 機架bash
6.Client 經過API後指令操做的一端(好比上傳或下載文件,操做文件)服務器
能夠經過shell或JavaAPI方式操做HDFS中的數據。架構
hdfs中的數據,一次寫入、屢次讀取、不支持行級別的增刪改。2.0版本增長了在文件中追加的內容的功能。因此也沒有對應的行級別的命令。
hadoop fs -ls /user #查看目錄。 hadoop fs -mkdir /user/trunk #建立目錄。 hadoop fs -lsr /user #遞歸查看目錄。 hadoop fs -put test.txt /user/trunk #上傳文件。 hadoop fs -put test.txt #複製到hdfs當前目錄下,首先要建立當前目錄。 hadoop fs -get /user/trunk/test.txt #複製到本地當前目錄下,即下載到本地當前目錄 hadoop fs -cat /user/trunk/test.txt #查看文件內容。 hadoop fs -tail /user/trunk/test.txt #監控,查看最後1000字節。 hadoop fs -rm /user/trunk/test.txt #刪除文件。 hadoop fs -rmdir /user/trunk #刪除目錄。 hadoop fs -help ls #查看ls命令的幫助文檔。
在Windows環境下,解壓一個Hadoop的安裝包,做爲Windows下的Hadoop單機模式使用。
若是要使用遠程的Hadoop須要配置Windows下的Hadoop的環境變量,以及用戶名的環境變量。配置此項可能須要重啓電腦。
內容以下:
HADOOP_HOME=路徑 PATH=%HADOOP_HOME%/bin;%HADOOP_HOME%/sbin HADOOP_USER_NAME=root
將插件文件hadoop-eclipse-plugin-2.7.1.jar放入eclipse/plugins目錄下,重啓eclipse。
在Window的preferences中找到Hadoop Map/Reduce,將單機模式的Hadoop路徑填入,以下如所示:
在Eclipse中找到以下界面,將Map/Reduce模式顯示出來。
在Hadoop的配置界面,填入以下數據:
Location name:填寫安裝Hadoop服務器的主機名。
Map/Reduce(V2)Master Host:填寫安裝Hadoop服務器的主機名。
DFS Master Port:改成安裝Hadoop服務器核心配置文件中配置的端口號,通常默認爲9000。
User name:安裝Hadoop服務器的超級管理員,通常爲root。
配置完成點擊Finish。而後就可使用了。
當遇到權限拒絕問題時,能夠修改hdfs-site.xml中的配置dfs.permissions爲false關閉hadoop的權限認證。
也能夠在windows的環境變量中配置HADOOP_USER_NAME指定鏈接hadoop時使用的名稱,這種方式配置完要重啓eclipse。
hadoop/share/hadoop/common/*.jar
hadoop/share/hadoop/common/lib/*.jar
hadoop/share/hadoop/hdfs/*.jar
文件系統類,HDFS API的主要類,全部相關操做基本都在這個類裏。
①重要方法
1)get(URI uri,Configuration conf);
獲取一個FileSystem對象。
2)open(Path path);
打開鏈接。返回一個InputStream對象。
3)create(Path path);
建立一個文件。返回一個OutputStream對象。
4)delete(Path path,boolean recursive);
是否遞歸刪除一個文件或路徑。返回boolean值,刪除成功返回true,刪除失敗返回false。
5)mkdirs(Path path);
建立文件夾,能夠建立多級目錄。返回boolean值,建立成功返回true,建立失敗返回false。
HDFS相關操做的一個工具類。
①重要方法
1)copyBytes(InputStream in,OutputStream out,int buffersize);
對接數據,將輸入輸出流整合,直接將文件傳輸到目的地。
@Test public void mkdir() throws Exception { FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration()); fs.mkdirs(new Path("/test2/xx/yy/zzz")); fs.close(); } @Test public void delete() throws Exception { // 1.建立文件系統對象 FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration()); // 2.刪除文件 // fs.delete(new Path("/test/3.txt")); fs.delete(new Path("/test/1.txt"), true); // 3.關閉鏈接 fs.close(); } @Test public void upload() throws Exception { // 1.建立文件系統對象 FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration()); // 2.建立文件 FSDataOutputStream out = fs.create(new Path("/test/3.txt")); // 3.建立輸入流 InputStream in = new FileInputStream("2.txt"); // 4.對接流 IOUtils.copyBytes(in, out, 1024); // 5.關閉流關閉文件系統 in.close(); out.close(); fs.close(); } @Test public void download() throws Exception { // 1.建立文件系統對象 FileSystem fs = FileSystem.get(new URI("hdfs://yun01:9000"), new Configuration()); // 2.獲取鏈接文件的流 FSDataInputStream in = fs.open(new Path("/test/jt-對象存儲地址.txt")); // 3.建立輸出流 OutputStream out = new FileOutputStream("2.txt"); // 對接流,傳輸數據 IOUtils.copyBytes(in, out, 1024); // 5.關閉流,關閉鏈接 out.close(); in.close(); fs.close(); }
將數據進行切塊後進行復制並存儲在集羣的多個節點中,從而實現了海量數據分佈式存儲,並經過block副本實現可靠性保證。
其中切出的塊稱爲Block。
負責存放Block的節點稱之爲DataNode節點。
負責存放元數據的節點稱之爲NameNode節點。
另外還有一個獨立進程稱做SecondaryNameNode負責幫助NameNode進行元數據的合併操做。
Block是HDFS中存儲的基本單位。
當文件被存儲到HDFS的過程當中,會先將文件按照指定大小來切塊即block,複製出指定數量的副本(默認是3個),分佈式存儲在集羣中。2.0版本中Block默認的大小爲128M,1.0版本中爲64M。
1.一個大文件切分爲小的若干個Block方便分佈式的存儲在不一樣磁盤中。
2.屏蔽了數據的區別,只須要面向Block操做,從而簡化存儲系統。
3.有利於數據的複製。每次複製的是一個體積較小的Block,而不是一個大型文件,效率更高。
若是切分事後,剩餘數據不夠128MB,則會將剩餘數據單獨做爲一個Block存儲,數據多大,Block就多大,128MB只是最大大小,不是固定大小。
例如:
一個256MB文件,共有256/128=2個Block。
一個258MB文件,共有258/128=2餘下2MB,則餘下的2MB會獨佔一個Block大小爲2MB,則且分出兩個128MB的Block和一個2MB的Block。
一個1MB文件,則單獨佔用一個Block,這個Block爲1MB大小。
第一個副本:若是是集羣內提交,就放置在上傳文件的DataNode,若是是集羣外就提交,隨機選擇一臺磁盤不太滿,cpu不太忙的節點,進行上傳。
第二個副本:放置在第一個副本不一樣機架的節點上。(利用機架感知策略)
第三個副本:放置在與第二個副本相同機架的節點上。
更多副本:隨機節點。
機架感知策略:
其實就是在Hadoop的配置文件中添加一個記錄ip和主機名映射機架的關係表,經過這張關係表來判斷那個主機是不一樣機架。
DataNode在整個HDFS中主要是存儲數據的功能。數據以Block的形式存放在DataNode中。
DataNode節點會不斷向NameNode節點發送心跳報告保持與其聯繫,心跳報告的頻率是3秒一次,在心跳報告中向NameNode報告信息,從心跳響應中接受NameNode的指令,執行對塊的複製、移動、刪除等操做。
NameNode若是10分鐘都沒收到DataNode的心跳,則認爲該DataNode已經lost,並向其餘DataNode發送備份block的指令,完成lost節點中的數據副本的複製,以保證數據副本數量在整個HDFS中是一致的。
全部的DataNode都是主動聯繫NameNode,NameNode不會主動聯繫DataNode。
NameNode維護着HDFS中的元數據信息。同時還兼顧各類外部請求以及DataNode中數據存儲的管理。
元數據信息包括:文件信息、目錄結構信息、副本數量信息、文件和Block之間關係的信息、Block和DataNode之間的關係信息。數據格式參照以下:
FileName replicas block-Ids id2host
例如:/test/a.log,3,{b1,b2},[{b1:[h0,h1,h3]},{b2:[h0,h2,h4]}]
NameNode中的元數據信息存儲在內存和文件中,內存中爲實時信息完整信息,文件中爲數據鏡像做爲持久化存儲使用,其中block和DataNode之間的關係信息不會在文件中存儲。
①內存中的元數據
文件信息、目錄結構信息、副本數量信息、文件和Block之間關係的信息、Block和DataNode之間的關係信息。
②文件中的元數據
文件信息、目錄結構信息、副本數量信息、文件和Block之間關係的信息。
能夠發現文件中的元數據比起內存中缺失了block和DataNode之間的對應關係,這是由於,HDFS集羣常常發生變更,DataNode增長或減小都是很正常狀況,所以這些信息都是臨時在內存中組織的,而不會存儲在磁盤鏡像文件中。
①fsimage
元數據鏡像文件。存儲某NameNode元數據信息,並非實時同步內存中的數據。
②edits
記錄NameNode對數據操做的日誌文件。
③fstime
保存最近一次checkpoint的時間。即最後一次元數據合併的時間。
當有寫請求時,NameNode會首先將請求操做寫edit log到磁盤edits文件中,成功後纔會修改內存,並向客戶端返回操做結果。
因此,fsimage中的數據並非實時的數據,而是在達到條件時要和edits文件合併,合併過程由SecondaryNameNode完成。
之因此不直接改fsimage而是要在edits中記錄,是由於記錄日誌是一種連續的磁盤IO操做,能夠節省時間。若是直接修改fsimage文件,會進行大量的不連續的磁盤IO操做,這樣會大大下降效率。
這個是爲分佈式纔有的角色,在徹底分佈式中,由JournalNode代替。
SecondaryNameNode並非NameNode的熱備份,而是協助者,幫助NameNode進行元數據的合併。
從另外的角度來看能夠提供必定的備份功能,但並非熱備,若是直接使用可能會丟失上一次合併後發生的數據!能夠從SecondaryNameNode中恢復部分數據,可是沒法恢復所有。
什麼時候出發數據合併?
根據配置文件設置的時間間隔:fs.checkpoint.period默認3600秒。
根據配置文件設置的edits log大小:fs.checkpoint.size默認64MB。
①拷貝文件
當達到合併數據的條件後,SecondrayNameNode會將NameNode中的fsimage和edits文件拷貝過來,同時NameNode中會建立一個新的edits.new文件,用於記錄新的讀寫請求。
②合併數據
在SecondrayNameNode中將拷貝過來的fsimage和edits合併爲一個新的fsimage.ckpt文件。
③傳回數據
SecondrayNameNode將合併完成的fsimage.ckpt文件拷貝回NameNode中,而後刪除以前的fsimage文件,將fsimage.ckpt文件改名爲fsimage,NameNode將原來edtis文件刪除,再將edtis.new改成edits,完成合並工做。
④記錄合併操做
最後在fstime文件中添加此次合併的記錄。
因爲NameNode實時數據都在內存中,此處的合併指的是磁盤中的持久化的數據的處理。
判斷:snn能夠對元數據作必定程度的備份,可是不是熱備,對不對?
思考:什麼狀況下可能形成NameNode元數據信息丟失?
snn並非nn的熱備,可是能保存大部分備份數據。緣由就在於edits.new中的數據丟失了就找不回來了
一般NameNode和SecondrayNameNode要放置到不一樣機器中以此提高性能,並提供必定的元數據安全性。
針對HDFS的不一樣操做,有不一樣的執行流程,具體介紹以下。
使用HDFS提供的客戶端開發庫Client,向遠程的Namenode發起RPC請求;NameNode會檢驗當前文件是否存在以及當前客戶端是否有權限讀取該文件,兩種檢查只中有一種不符合條件,就會拋出異常,再也不進行下一步操做。
若是以上校驗沒有問題,Namenode會視狀況返回文件的部分或者所有block列表,對於每一個block,Namenode都會返回有該block副本的DataNode地址。
客戶端開發庫Client會選取離客戶端最接近(並非物理上的最近,而是延遲最低負載最低)的DataNode來讀取block;若是客戶端自己就是DataNode,那麼將從本地直接獲取數據。
讀取完當前block的數據後,會進行checksum驗證,若是讀取datanode時出現錯誤,客戶端會通知Namenode,而後再從下一個擁有該block拷貝的datanode繼續讀。
當讀取正確的block數據以後,關閉與當前的DataNode鏈接,併爲讀取下一個block尋找最佳的DataNode;當讀完列表的block後,且文件讀取尚未結束,客戶端開發庫會繼續向Namenode獲取下一批的block列表。
當文件最後一個塊也都讀取完成後,datanode會鏈接namenode告知關閉文件。
NameNode不參與讀取真實數據傳輸的過程。
使用HDFS提供的客戶端開發庫Client,向遠程的Namenode發起RPC請求;Namenode會檢查要建立的文件是否已經存在,建立者是否有權限進行操做,若是這兩個條件有一個不符合就會讓客戶端拋出異常,終止操做。條件驗證經過則會爲文件建立一個記錄。
當客戶端開始寫入文件的時候,開發庫客戶端會將文件切分紅多個packets,並在內部以數據隊列"data queue"的形式管理這些packets,而後向Namenode申請新的blocks,獲取用來存儲replicas的合適的datanodes列表,列表的大小根據在Namenode中對replication的設置而定。
根據DataNode列表鏈接DataNode節點,開始以pipeline(管道)的形式將packet寫入全部的replicas中。客戶端把packet以流的方式寫入第一個datanode,該datanode把該packet存儲以後,再將其傳遞給在此pipeline中的下一個datanode,直到最後一個datanode完成存儲,這種寫數據的方式呈流水線的形式。
最後一個datanode成功存儲以後會返回一個ack packet,在pipeline裏傳遞至客戶端,在客戶端的開發庫內部維護着"ack queue",成功收到datanode返回的ack packet後會從"ack queue"移除相應的packet。
若是傳輸過程當中,有某個datanode出現了故障,那麼當前的pipeline會被關閉,出現故障的datanode會從當前的pipeline中移除,剩餘的block會繼續剩下的datanode中繼續以pipeline的形式傳輸,同時Namenode會分配一個新的datanode,保持replicas設定的數量。
當全部的packges都成功的上傳後,客戶端通知NameNoe文件上傳完成,NameNode將該文件置爲可用狀態,並關閉該文件。
NameNode不參與真實數據存儲傳輸的過程。
客戶端發起請求鏈接NameNode表示要刪除文件,NameNode檢查文件是否存在及是否有權限刪除文件,若是條件驗證不經過,那麼拋出異常,終止操做。若是經過則進行下一步操做。
NameNode執行元數據的刪除,只是將該元數據置爲已刪除狀態,而後向客戶端表示文件刪除成功。
當保存着這些數據塊的DataNode節點向NameNode節點發送心跳時,在心跳響應中,NameNode節點會向DataNode發出指令,要求刪除這些block。DataNode收到指令後刪除對應的Block。因此在執行完delete方法後的一段時間內,數據塊才能被真正的刪除掉。
當該文件對應的全部block及其副本都被刪除後,NameNode中將以前標記爲已刪除的元數據刪除。
在HDFS啓動時,NameNode先合併fsImage和edits文件,生成新的fsimage和空的edits文件,這個過程是NameNode本身進行的。而後再將fsimage中的數據恢復到內存中,但此時內存中的元數據並不夠,還差block和datanode的映射關係,這個信息在fsimage中是不存在的,須要臨時在內存中組織出來。
此時NameNode等待DataNode的鏈接,DataNode在啓動時會向NameNode發送心跳報告,其中攜帶本身具備的Block的編號信息,NameNode基於這些信息,在內存中組織元數據信息。
直到NameNode達到最小啓動條件後,進行必要的block副本複製和刪除,以後開始對外提供服務。整個這個過程當中,HDFS沒法正常工做,稱之爲處在安全模式中。
NameNode最小啓動條件:每一個Block都至少有了一個副本被找到。
在啓動HDFS時,會當即進入安全模式,此時不能操做hdfs中的文件,只能查看目錄文件名等,讀寫操做都不能進行。
在HDFS正常運行過程當中,若是由於意外狀況,形成有block找不到任何副本,則HDFS進入安全模式。
org.apache.hadoop.dfs.SafeModeException: Cannot delete /user/hadoop/input. Name node is in safe mode
安全模式實際上是HDFS對元數據的一種保護機制,防止意外的操做損壞元數據。
當遇到安全模式,最簡單的辦法就是等一會。
若是很長時間都沒法退出安全模式,則應檢查進入安全模式的緣由,找到問題的緣由解決,則hadoop會自動退出安全模式。
若是非要強制退出安全模式,可使用以下命令,可是要慎用,一不當心損壞了元數據,hdsf中的數據就都沒法使用了:
hadoop dfsadmin -safemode leave
慎用!
支持超大文件。超大文件在這裏指的是幾百M,幾百GB,甚至幾TB大小的文件。通常來講hadoop的文件系統會存儲TB級別或者PB級別的數據。因此在企業的應用中,數據節點有可能有上千個。
在集羣的環境中,硬件故障是常見的問題。由於有上千臺服務器鏈接在一塊兒,這樣會致使高故障率。所以故障檢測和自動恢復是HDFS文件系統的一個設計目標。
HDFS的數據處理規模比較大,應用一次須要訪問大量的數據,同時這些應用通常都是批量處理,而不是用戶交互式處理。應用程序能以流的形式訪問數據集。主要的是數據的吞吐量,而不是訪問速度。
大部分HDFS操做文件時,須要一次寫入,屢次讀取。在HDFS中,一個文件一旦通過建立、寫入、關閉後,通常就不須要修改了。這樣簡單的一致性模型,有利於提升吞吐量。
數據自動保存多個副本,副本丟失後自動恢復。
構建在廉價機器上,能夠輕鬆的經過擴展機器數量,來近乎線性的提升集羣存儲能力。
低延遲數據如:和用戶進行交互的應用,須要數據在毫秒或秒的範圍內獲得響應。因爲hadoop針對高數據吞吐量作了優化,犧牲了獲取數據的延遲,因此對於低延遲來講,不適合用hadoop來作。
HDFS支持超大的文件,是經過數據分佈在數據節點,數據的元數據保存在名字節點上。名字節點的內存大小,決定了HDFS文件系統可保存的文件數量。雖然如今的系統內存都比較大,但大量的小文件仍是會影響名字節點的性能。
HDFS的文件只能有一次寫入,不支持修改和追加寫入(2.0版本支持追加),也不支持修改。只有這樣數據的吞吐量才能大。
沒有像關係型數據庫那樣,對事務有強有力的支持。
上一篇:Hadoop徹底分佈式集羣搭建