HDFS分佈式文件系統,即Hadoop Distributed Filesystem,是一個分佈式文件系統,被設計部署在廉價硬件上。HDFS是一個高容錯,被設計部署在廉價硬件上。HDFS提供高吞吐量訪問數據,而且適用於大數據集應用程序。HDFS提供POSIX(可移植性操做系統接口)標準流式數據訪問。html
硬件故障做爲常態處理,而不是做爲異常。整個HDFS系統可能包含成百上千的服務器,每一個服務器都存儲了文件系統的一部分。系統包含如此多的組成部分,每一個組成部分都會頻繁地出現故障,這意味着HDFS的一些組成部分老是失效的。快速的故障檢測和自動修復是HDFS的核心架構目標。java
運行在HDFS上的應用程序必須流式的訪問數據集。他們並非運行在常規文件系統上的常規程序。HDFS的設計更適合進行批處理做業,而不是用戶交互式的;重點在於數據訪問的高吞吐量而不是數據訪問的低延遲。POSIX強制的不少硬性需求對不少應用來講不是必需的,去掉POSIX的不少關鍵地方的語義,能夠得到更好的數據吞吐量。node
運行在HDFS上的應用程序都是大型數據集。這意味着典型的HDFS文件大小是從GB到TB級別。所以,HDFS在單個集羣中就能提供高聚合數據帶寬和數百個節點的規模,能支持一個集羣中千萬級的文件數。apache
大部分的HDFS程序對於文件操做都是一次寫入屢次讀取。文件一旦建立、寫入、關閉以後就不須要進行修改了。這個假定簡化了數據一致性問題,而且支持高吞吐量的訪問。Mapreduce和網絡爬蟲程序都是很是完美地符合這個模型。bootstrap
一個程序請求的計算,若是能在更接近數據存儲的位置進行,那麼將會更有效率。尤爲是在大數據量狀況下,這樣能夠最小化網絡擁塞和提升整個系統的吞吐量。這個假定就是將計算離數據更近比將文件移動到程序運行的位置更好。HDFS提供了接口,讓程序將本身移動到離數據存儲更近的位置運行。api
HDFS被設計成能夠方便的從一個平臺移植到另一個平臺,這樣有助於HDFS被更多的大數據集應用程序採用。瀏覽器
HDFS是一種Master/Slave架構。一個HDFS集羣有一個獨立的Namenode,這個Master用來管理文件系統的命名空間和客戶端的文件訪問。另外,集羣中還有一些Datanodes,通常來講每一個Datanode管理本節點上的存儲(磁盤)。HDFS暴露一個文件文件系統命名空間,而且容許用戶數據存儲成文件。在HDFS內部,一個文件將被切分紅一個或者多個數據塊,而這些數據塊被存儲在一組Datanodes中。Namenode執行名字空間的文件和目錄的操做,好比打開、關閉和重命名;它同時決定了數據塊在數據節點上的映射分佈。Datanodes負責爲文件系統客戶端的讀寫請求提供服務。根據Namenode的指示,Datanodes同時扮演了建立、刪除和複製數據塊的角色。緩存
一言以蔽之,Namenode存儲名字空間。Datanodes存儲文件系統數據塊。Namenode控制文件系統的訪問,Datanode響應Namenode的指示來操做數據塊。安全
Namenode和Datanode分別運行在普通的機器上。典型的就是GNU/Linux操做系統。使用JAVA語言編寫,任何支持JAVA的機器(理論上)都能運行Namenode和Datanode。高度移植語言JAVA的好處在於HDFS能夠部署在大範圍的機器上。典型的部署是,一臺單獨的機器部署Namenode,其餘機器部署Datanode。服務器
集羣內部單個Namenode的存在極大地簡化了系統體系。Namenode做爲仲裁員,而且是全部HDFS元數據的存儲倉庫。系統這樣設計可使得用戶實際數據沒必要通過Namenode。
The File System Namespace即文件系統命名空間。
HDFS支持傳統繼承式的文件組織結構。用戶或者程序能夠建立目錄而且把文件存儲在這些目錄中。HDFS的名字空間層次結構跟大多數文件系統很是類似:建立、刪除、從一個目錄挪動文件到另外一個目錄以及重命名。
Namenode維護文件系統命名空間。任何文件系統名字空間或者屬性的改變都會被Namenode記錄。應用程序能夠指定文件在HDFS中的副本數。文件的副本數因子都是由Namenode進行存儲。
HDFS經過塊序列的形式存儲每個文件,除了最後一個塊的其餘塊都保持相同的大小。塊的大小和副本數能夠爲每一個文件單獨配置,副本數能夠在建立以後進行修改。HDSF中的文件都是嚴格地要求任什麼時候候只有一個寫操做。Namenode支配Datanode進行數據塊的複製,而且週期性地接受Datanode發送的心跳和塊報告。一個塊報告包括該數據節點的全部塊列表。
副本位置的選擇嚴重影響HDFS的可靠性和性能。
HDFS的副本分佈採用了機架感知(Hadoop Rack Awareness)分佈策略,這就保證了集羣數據的可靠性,可用性和網絡帶寬利用率。大型的HDFS實例運行的服務器集羣,一般分佈在不一樣的機架上。邏輯機架每一個對應一個交換機,不一樣機架之間的通信也是經過匯聚網絡交換機實現的。大多數狀況下,同一個機架內機器之間的網絡帶寬要比不一樣機架機器的網絡帶寬要高。
Namenode經過機架感知的過程決定了每一個Datanode所屬的Rack id.一個簡單而無優化的策略就是將副本分配到不一樣的rack上。這種分佈策略能夠避免當一整個機架故障時出現的數據丟失,也能在讀數據時最大化的利用不一樣機架的帶寬。可是這種策略增長了寫成本,由於一個寫須要將數據塊副本發送到不一樣的機架上。
一般狀況下,副本因子設置爲3。HDFS的分佈策略是將第一個塊寫入一個機架服務器上,將第二個塊寫入同機架的另外一個機器,將第三個塊寫入另外一個機架的服務器上。這種策略將機架內部通信切分出來單獨處理一般可以提高寫性能。機架故障的概率要遠遠小於機器故障的概率。這種策略不會影響數據可靠性和可用性;然而它卻減小了數據讀取時消耗的匯聚網絡帶寬,由於一個塊只分布在兩個單獨的機架上而不是三個。這種策略在沒有影響數據可靠性和讀取性能的前提下,提高了寫入性能。
邏輯機架策略的設置能夠經過腳本進行單獨設置,這一部分咱們在集羣管理的章節再作進一步的詳細描述。
http://hadoop.apache.org/docs/current/hadoop-project-dist//hadoop-common/RackAwareness.html
爲了減小全局網絡帶寬消耗和讀取延遲,HDFS儘可能知足讀取請求在距離最近的副本位置進行。讀取請求發生時,本機架的服務器上副本要優先於其餘機架上的副本。
HDFS啓動時,Namenode會進入稱爲安全模式的特殊狀態。當Namenode處於安全模式時,不會發生數據塊的複製。Namenode接受數據節點的心跳信息和數據塊報告。每一個數據塊都設置了單獨的副本數。
dfs.replication:默認塊副本數。實際副本數能夠在文件建立時指定,若是沒有指定將使用默認值。
dfs.namenode.replication.min:數據塊最小副本數。
dfs.replication.max:數據塊最大副本數。
dfs.safemode.threshold.pct:指定應有多少比例的數據塊知足最小副本數要求。小於等於0意味不進入安全模式,大於1意味一直處於安全模式。
副本數按dfs.replication設置,若是有失效節點致使某數據塊副本數下降,當低於dfs.namenode.replication.min後,系統再在其餘節點處複製新的副本。若是該數據塊的副本常常丟失,致使在環境中太多的節點處複製了超dfs.replication.max的副本數,那麼就再也不復制了。
hadoop的安全模式即只讀模式,是指當前系統中數據塊的副本數比較少,在該階段要對數據塊進行復制操做,不允外界對數據塊進行修改和刪除等操做。 可是當最小副本數設置爲1時,安全模式意味着數據塊不完整,也不能發生複製操做。NameNode在啓動的時候首先進入安全模式,若是datanode丟失的block達到必定的比例(dfs.safemode.threshold.pct),則系統會一直處於安全模式狀態即只讀狀態。 dfs.safemode.threshold.pct(缺省值0.999f)表示HDFS啓動的時候,若是DataNode上報的block個數達到了元數據記錄的block個數的0.999倍才能夠離開安全模式,不然一直是這種只讀模式。若是設爲1則HDFS永遠是處於SafeMode。
HDFS的名字空間是在Namenode上存儲的。Namenode使用稱之爲EditsLog的事務日誌來持久化每次發生在文件系統的修改。完整的文件系統名字空間、文件塊的映射和文件系統的配置都存在一個叫FsImage的文件中,FsImage也是在Namenode的本地文件系統中儲存。
Namenode在內存中有一個完整的文件系統名字空間,和文件塊的映射鏡像。這個元數據設計緊湊,4GB內存的Namenode也能輕鬆處理很是大的文件數和目錄。當名字空間啓動時,它將從磁盤中讀取FsImage和EditsLog文件,而後將新的元數據刷新到本地磁盤中,生成一個新的FsImage文件,至此EditsLog文件已經被處理並持久化到FsImage中,這個過程叫作檢查點。檢查點一般發生到Namenode啓動的時候;而且會週期性地進行檢查點操做,默認3600;當事務數默認達到1000000的時候也會處罰檢查點操做。
Datanode將HDFS數據以文件的形式存儲在本地的文件系統中,它並不知道有關HDFS文件的信息。它把每一個HDFS數據塊存儲在本地文件系統的一個單獨的文件中。Datanode並不在同一個目錄建立全部的文件,實際上,它用試探的方法來肯定每一個目錄的最佳文件數目,而且在適當的時候建立子目錄。在同一個目錄中建立全部的本地文件並非最優的選擇,這是由於本地文件系統可能沒法高效地在單個目錄中支持大量的文件。當一個Datanode啓動時,它會掃描本地文件系統,產生一個這些本地文件對應的全部HDFS數據塊的列表,而後做爲報告發送到Namenode,這個報告就是塊狀態報告。
全部的HDFS通信協議都是創建在TCP/IP協議之上。客戶端經過一個可配置的TCP端口鏈接到Namenode,經過ClientProtocol協議與Namenode交互。而Datanode使用DatanodeProtocol協議與Namenode交互。一個遠程過程調用(RPC)模型被抽象出來封裝ClientProtocol和Datanodeprotocol協議。
在設計上,Namenode不會主動發起RPC,而是響應來自客戶端或 Datanode 的RPC請求。
HDFS的主要目標就是即便在出錯的狀況下也要保證數據存儲的可靠性。常見的三種出錯狀況是:Namenode出錯, Datanode出錯和網絡割裂(network partitions)。
每一個Datanode節點週期性地向Namenode發送心跳信號。網絡割裂可能致使一部分Datanode跟Namenode失去聯繫。Namenode經過心跳信號的缺失來檢測這一狀況,並將這些近期再也不發送心跳信號Datanode標記爲宕機,不會再將新的IO請求發給它們。任何存儲在宕機Datanode上的數據將再也不有效。Datanode的宕機可能會引發一些數據塊的副本系數低於指定值,Namenode不斷地檢測這些須要複製的數據塊,一旦發現就啓動複製操做。
在下列狀況下,可能須要從新複製:某個Datanode節點失效,某個副本遭到損壞,Datanode上的硬盤錯誤,或者文件的副本系數增大。
HDFS的架構支持數據均衡策略。當數據節點之間的空間佔用比例超過一個設定的閾值時,能夠手動啓動balancer程序,就會自動地將數據從空間佔用比例較大的Datanode移動到其餘較空閒的Datanode。
在hadoop2.0中,datanode數據副本存放磁盤選擇策略有兩種方式:第一種是沿用hadoop1.0的磁盤目錄輪詢方式,實現類:RoundRobinVolumeChoosingPolicy.java;第二種是選擇可用空間足夠多的磁盤方式存儲,實現類:AvailableSpaceVolumeChoosingPolicy.java。
若是不配置,默認使用第一種方式,既輪詢選擇磁盤來存儲數據副本,可是輪詢的方式雖然可以保證全部磁盤都可以被使用,可是常常會出現各個磁盤直接數據存儲不均衡問題,有的磁盤存儲得很滿了,而有的磁盤可能還有不少存儲空間沒有獲得利用,全部在hadoop2.0集羣中,最好將磁盤選擇策略配置成第二種,根據磁盤空間剩餘量來選擇磁盤存儲數據副本,這樣同樣能保證全部磁盤都能獲得利用,還能保證全部磁盤都被利用均衡。當配置AvailableSpaceVolumeChoosingPolicy時,還有額外的兩個相關參數:dfs.datanode.available-space-volume-choosing-policy.balanced-space-threshold;
dfs.datanode.available-space-volume-choosing-policy.balanced-space-preference-fraction。
從某個Datanode獲取的數據塊有多是損壞的,損壞多是由Datanode的存儲設備錯誤、網絡錯誤或者軟件bug形成的。HDFS客戶端軟件實現了對HDFS文件內容的校驗和(checksum)檢查。當客戶端建立一個新的HDFS文件,會計算這個文件每一個數據塊的校驗和,並將校驗和做爲一個單獨的隱藏文件保存在同一個HDFS名字空間下。當客戶端獲取文件內容後,它會檢驗從Datanode獲取的數據跟相應的校驗和文件中的校驗和是否匹配,若是不匹配,客戶端能夠選擇從其餘Datanode獲取該數據塊的副本。
FsImage和Editlog是HDFS的核心數據結構。若是這些文件損壞了,整個HDFS實例都將失效。於是,Namenode能夠配置成支持維護多個FsImage和Editlog的副本。任何對FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操做可能會下降Namenode每秒處理的名字空間事務數量。然而這個代價是能夠接受的,由於即便HDFS的應用是數據密集的,它們也非元數據密集的。
HADOOP2.0中添加的QJM等高可用方式,進一步保證了元數據的安全性。 當其中一個Namenode節點的元數據磁盤損壞時,咱們只須要更換目錄或者磁盤,將另外一個可用Namenode的元數據同步回來便可。HDFS系統在其中一個Namenode元數據損壞時依然可以對外提供服務。
快照支持某一特定時刻的數據的複製備份。利用快照,可讓HDFS在數據損壞時恢復到過去一個已知正確的時間點。
快照可用於整個文件系統,也可只用於部分文件系統。快照最廣泛的用途是數據備份,防止用戶錯誤和災難恢復。
操做系統下普通的文件系統(如ext4)都是基於數據塊的,數據塊是磁盤進行數據讀寫的最小單位。構建在磁盤上的文件系統都是使用磁盤塊來管理文件系統的塊,通常文件系統的大小能夠是磁盤塊的整數倍。
HDFS也有數據塊的概念,是HDFS對於文件系統抽象出來的概念。最初默認大小是64MB,較新版本默認大小是128MB.與磁盤塊的概念相似,HDFS上存儲的文件也被劃分紅基於塊大小的多個分塊。可是與普通文件系統不一樣的是,HDFS上的塊若是小於設置的塊大小時,並不會真正佔用整個塊的實際存儲空間。
HDFS的塊放的比較大,主要是爲了把尋道時間最小化。若是一個塊足夠大,那麼硬盤傳輸數據的時間遠遠大於尋找塊的起始位置的時間。這樣就使得HDFS的數據傳輸速度與硬盤的傳輸速度更加接近。
客戶端建立文件的請求其實並無當即發送給Namenode,事實上,在剛開始階段HDFS客戶端會先將文件數據緩存到本地的一個臨時文件。應用程序的寫操做被透明地重定向到這個臨時文件。當這個臨時文件累積的數據量超過一個數據塊的大小,客戶端纔會聯繫Namenode。Namenode將文件名插入文件系統的層次結構中,而且分配一個數據塊給它。而後返回Datanode的標識符和目標數據塊給客戶端。接着客戶端將這塊數據從本地臨時文件上傳到指定的Datanode上。當文件關閉時,在臨時文件中剩餘的沒有上傳的數據也會傳輸到指定的Datanode上。而後客戶端告訴Namenode文件已經關閉。此時Namenode纔將文件建立操做提交到日誌裏進行存儲。若是Namenode在文件關閉前宕機了,則該文件將丟失。
上述方法是對在HDFS上運行的目標應用進行認真考慮後獲得的結果。這些應用須要進行文件的流式寫入。若是不採用客戶端緩存,因爲網絡速度和網絡堵塞會對吞估量形成比較大的影響。這種方法並非沒有先例的,早期的文件系統,好比AFS,就用客戶端緩存來提升性能。爲了達到更高的數據上傳效率,已經放鬆了POSIX標準的要求。
當客戶端向HDFS文件寫入數據的時候,一開始是寫到本地臨時文件中。假設該文件的副本系數設置爲3,當本地臨時文件累積到一個數據塊的大小時,客戶端會從Namenode獲取一個Datanode列表用於存放副本。而後客戶端開始向第一個Datanode傳輸數據,第一個Datanode一小部分一小部分(4 KB)地接收數據,將每一部分寫入本地倉庫,並同時傳輸該部分到列表中第二個Datanode節點。第二個Datanode也是這樣,一小部分一小部分地接收數據,寫入本地倉庫,並同時傳給第三個Datanode。最後,第三個Datanode接收數據並存儲在本地。所以,Datanode能流水線式地從前一個節點接收數據,並在同時轉發給下一個節點,數據以流水線的方式從前一個Datanode複製到下一個。
HDFS給應用提供了多種訪問方式。用戶能夠經過Java API接口訪問,也能夠經過C語言的封裝API訪問,還能夠經過瀏覽器的方式訪問HDFS中的文件。
用戶能夠設置回收站生效,當用戶或應用程序刪除某個文件時,這個文件並無馬上從HDFS中刪除。實際上,HDFS會將這個文件重命名轉移到/trash目錄。只要文件還在/trash目錄中,該文件就能夠被迅速地恢復。文件在/trash中保存的時間是可配置的,當超過這個時間時,Namenode就會將該文件從名字空間中刪除。刪除文件會使得該文件相關的數據塊被釋放。
注意,從用戶刪除文件到HDFS空閒空間的增長之間會有必定時間的延遲。
只要被刪除的文件還在/trash目錄中,用戶就能夠恢復這個文件。若是用戶想恢復被刪除的文件,能夠瀏覽/trash目錄找回該文件。
/trash目錄與其餘的目錄沒有什麼區別,除了一點:在該目錄上HDFS會應用一個特殊策略來自動刪除文件。
/trash目錄僅僅保存被刪除文件的最後副本。回收站只能做爲用戶失誤致使的文件恢復,時效性短,並不能做爲數據安全的全量保證。
若是考慮數據全量安全性的數據備份,應考慮使用snapshot來實現。
當一個文件的副本系數被減少後,Namenode會選擇過剩的副本刪除。下次心跳檢測時會將該信息傳遞給Datanode。Datanode遂即移除相應的數據塊,集羣中的空閒空間加大。
一樣,在調用setReplication API結束和集羣中空閒空間增長間會有必定的延遲。
在HADOOP2.0以前,Namenode在HDFS集羣內是一個單點故障。每一個集羣都有一個Namenode,若是這個Namenode變得不可用,那麼HDFS整個將變得不可用,直到Namenode重啓或者遷移至另外一個機器上。
這與集羣的可用性在兩個主要方面有衝突:
意外事件(如非計劃停機)致使集羣不可用,直至Namenode重啓爲止。
計劃內維護性工做如在Namenode上進行軟件或者硬件升級會致使集羣停機時間。
HDFS高可用特性旨在經過運行兩個冗餘的Namenode來解決以上問題,經過一個主從配置來進行一個Namenode的熱備。當一個機器崩潰或者須要進行維護性工做的時候,這樣容許一個新Namenode的快速恢復。
在一個典型的HA集羣中,配置兩個獨立的Namenode節點服務器。任什麼時候候,一個Namenode處於Active狀態,其餘的處於Stanby狀態。Acitve Namenode來響應集羣中來自客戶端的操做,而Stanby只是扮演一個slave的狀態,維護足夠的狀態來在必要時提供一個快速故障恢復。
爲了使得Standby節點可以維持來自Active節點的狀態同步,兩個節點之間須要一組獨立的Journalnode來進行通訊。當Acitve節點上產生任何的名字空間更改,它持續的記錄更改到大部分Journalnode上。Standby節點可以讀取Journalnode的Edits文件,而且持續不斷的監控Edit Log的改變。Standby節點會將從Jouranlnode上所見的Edits應用到本身的名字空間。在故障轉移的過程當中,Standby將確認它已經從Journalnode上讀取了所有的Edits更改,而後會將本身切換成Active狀態。這能確保名字空間在故障轉移發生時可以徹底同步。
爲了提供一個快速的故障轉移,Standby節點必須實時地獲取集羣內全部塊的位置。爲了實現這個,全部的Datanode同時配置了兩個Namenode的位置,而且同時發送和心跳塊位置信息。
對於HA集羣里正確的操做,只有一個節點保持活躍,是相當重要的。不然,名字空間的狀態可能會在二者之間很快出現分歧,致使數據丟失或其餘不正確的結果。爲了確保性能且防止所謂的「裂腦情景」,Journalnodes只容許同一時間只有一個節點執行寫入操做。故障轉移期間,NameNode爲了切換爲Acitve狀態,只要簡單地接管Journalnodes寫入角色,這將有效地防止其餘Namenode節點繼續處於Active狀態,這使得新Active節點可以安全地進行故障轉移。
爲了部署HA集羣,你應該準備以下硬件資源。
兩臺機器用來運行你的Active和Standby節點。兩個節點應具備相同的硬件,保持與非HA集羣一樣的硬件配置要求。
多臺機器上運行你的Journalnodes。Journalnode守護進程是相對較輕,因此這些程序能夠與其餘Hadoop守護進程公用機器。
必須有至少3 個Journalnode守護進程,由於Edits Log的修改必須通過大多數Journalnodes。這將容許系統容忍一臺journal機器的故障。你也能夠運行超過3 Journalnodes,但爲了真正提升故障系統能夠容忍的數量,你應該運行JNS奇數,(即3,5,7,等)
當運行N journalnodes,系統能夠容忍最多(n - 1)/ 2的失敗和繼續正常。
自動故障轉移增長了兩個新的組件到HDFS部署中,分別是Zookeeper和ZKFailoverController過程(簡稱ZKFC)。ZKFailoverController(ZKFC)是一個新的組件,做爲Zookeeper客戶端同時監控和管理Namenode節點的狀態。Namenode節點上須要同時運行ZKFC。
Failure detection:集羣中每一個Namenode持續維持一個Zookeeper會話。若是機器崩潰,Zookeeper回話將退出,這樣通知其餘Namenode節點觸發故障轉移。
Active NameNode election:Zookeeper提供了一種簡單的機制來選擇其中一個節點做爲Active狀態。若是當前Active NameNode節點崩潰,另外一個節點可能須要在Zookeeper中持有一個特殊排他鎖,來代表應成爲下一個Active節點。
Health monitoring: ZKFC按期對本地Namenode執行健康檢查命令。只要Namenode節點及時響應一個健康情況,ZKFC則認爲考慮Namenode是健康狀態。若是Namenode節點已經崩潰,凍結,或進入了一個不健康的狀態,健康監測將標記其爲不健康。
ZooKeeper session management:當本地NameNode處於健康狀態時,ZKFC將與Zookeeper一直保持open回話。若是本地Namenode節點是Active的,它還擁有一個特殊的「鎖」Znode。該鎖使用的是Zookeeper的「ephemeral」(短暫)節點;若是session過時,鎖的節點將被自動刪除。
ZooKeeper-based election:若是本地Namenode節點是健康的,而且ZKFC查看Zookeeper發現沒有其餘節點獲取了鎖znode,它會嘗試獲取鎖。若是它成功了,那麼它已經「贏得選舉」,並負責運行故障轉移使本地Namenode節點變爲Active狀態。故障轉移過程相似於上述的手動故障轉移:第一,先前的活動是圍欄,若是必要的話,那麼當地的NameNode過渡到活動狀態。
在自動故障轉移設計的更多細節,請參閱Apache HDFS JIRA鏈接到hdfs-2185設計文檔。
如下是經過QJM建立HA集羣或者從單點Namenode切換爲HA集羣的一些部署細節:
若是你將一個非HA NameNode 轉換爲HA集羣,你應該首先運行命令「hdfs -initializeSharedEdits」,它會用本地Namenode Edits目錄的數據來初始化Journalnodes。