摘要: 概述:HDFS即Hadoop Distributed File System分佈式文件系統,它的設計目標是把超大數據集存儲到分佈在網絡中的多臺普通商用計算機上,而且可以提供高可靠性和高吞吐量的服務。分佈式文件系統要比普通磁盤文件系統複雜,由於它要引入網絡編程,分佈式文件系統要容忍...編程
概述:HDFS即Hadoop Distributed File System分佈式文件系統,它的設計目標是把超大數據集存儲到分佈在網絡中的多臺普通商用計算機上,而且可以提供高可靠性和高吞吐量的服務。分佈式文件系統要比普通磁盤文件系統複雜,由於它要引入網絡編程,分佈式文件系統要容忍節點故障也是一個很大的挑戰。安全
HDFS主要由3個組件構成,分別是NameNode、SecondaryNameNode和DataNode,HSFS是以master/slave模式運行的,其中NameNode、SecondaryNameNode 運行在master節點,DataNode運行slave節點。markdown
磁盤數據塊是磁盤讀寫的基本單位,與普通文件系統相似,hdfs也會把文件分塊來存儲。hdfs默認數據塊大小爲64MB,磁盤塊通常爲512B,hdfs塊爲什麼如此之大呢?塊增大能夠減小尋址時間與文件傳輸時間的比例,若尋址時間爲10ms,磁盤傳輸速率爲100MB/s,那麼尋址與傳輸比僅爲1%。固然,磁盤塊太大也很差,由於一個MapReduce一般以一個塊做爲輸入,塊過大會致使總體任務數量太小,下降做業處理速度。網絡
數據塊是存儲在DataNode中的,爲了可以容錯數據塊是以多個副本的形式分佈在集羣中的,副本數量默認爲3,後面會專門介紹數據塊的複製機制。架構
hdfs按塊存儲還有以下好處:併發
當一個客戶端請求一個文件或者存儲一個文件時,它須要先知道具體到哪一個DataNode上存取,得到這些信息後,客戶端再直接和這個DataNode進行交互,而這些信息的維護者就是NameNode。負載均衡
NameNode管理着文件系統命名空間,它維護這文件系統樹及樹中的全部文件和目錄。NameNode也負責維護全部這些文件或目錄的打開、關閉、移動、重命名等操做。對於實際文件數據的保存與操做,都是由DataNode負責。當一個客戶端請求數據時,它僅僅是從NameNode中獲取文件的元信息,而具體的數據傳輸不須要通過NameNode,是由客戶端直接與相應的DataNode進行交互。tcp
NameNode保存元信息的種類有:分佈式
須要注意的是,NameNode元信息並不包含每一個塊的位置信息,這些信息會在NameNode啓動時從各個DataNode獲取並保存在內存中,由於這些信息會在系統啓動時由數據節點重建。把塊位置信息放在內存中,在讀取數據時會減小查詢時間,增長讀取效率。NameNode也會實時經過心跳機制和DataNode進行交互,實時檢查文件系統是否運行正常。不過NameNode元信息會保存各個塊的名稱及文件由哪些塊組成。oop
通常來講,一條元信息記錄會佔用200byte內存空間。假設塊大小爲64MB,備份數量是3 ,那麼一個1GB大小的文件將佔用16*3=48個文件塊。若是如今有1000個1MB大小的文件,則會佔用1000*3=3000個文件塊(多個文件不能放到一個塊中)。咱們能夠發現,若是文件越小,存儲同等大小文件所須要的元信息就越多,因此,Hadoop更喜歡大文件。
在NameNode中存放元信息的文件是 fsimage。在系統運行期間全部對元信息的操做都保存在內存中並被持久化到另外一個文件edits中。而且edits文件和fsimage文件會被SecondaryNameNode週期性的合併(合併過程會在SecondaryNameNode中詳細介紹)。
運行NameNode會佔用大量內存和I/O資源,通常NameNode不會存儲用戶數據或執行MapReduce任務。
爲了簡化系統的設計,Hadoop只有一個NameNode,這也就致使了hadoop集羣的單點故障問題。所以,對NameNode節點的容錯尤爲重要,hadoop提供了以下兩種機制來解決:
DataNode是hdfs中的worker節點,它負責存儲數據塊,也負責爲系統客戶端提供數據塊的讀寫服務,同時還會根據NameNode的指示來進行建立、刪除、和複製等操做。此外,它還會經過心跳按期向NameNode發送所存儲文件塊列表信息。當對hdfs文件系統進行讀寫時,NameNode告知客戶端每一個數據駐留在哪一個DataNode,客戶端直接與DataNode進行通訊,DataNode還會與其它DataNode通訊,複製這些塊以實現冗餘。
NameNode和DataNode架構圖
須要注意,SecondaryNameNode並非NameNode的備份。咱們從前面的介紹已經知道,全部HDFS文件的元信息都保存在NameNode的內存中。在NameNode啓動時,它首先會加載fsimage到內存中,在系統運行期間,全部對NameNode的操做也都保存在了內存中,同時爲了防止數據丟失,這些操做又會不斷被持久化到本地edits文件中。
Edits文件存在的目的是爲了提升系統的操做效率,NameNode在更新內存中的元信息以前都會先將操做寫入edits文件。在NameNode重啓的過程當中,edits會和fsimage合併到一塊兒,可是合併的過程會影響到Hadoop重啓的速度,SecondaryNameNode就是爲了解決這個問題而誕生的。
SecondaryNameNode的角色就是按期的合併edits和fsimage文件,咱們來看一下合併的步驟:
最後再總結一下整個過程當中涉及到NameNode中的相關文件
HDFS經過備份數據塊的形式來實現容錯,除了文件的最後一個數據塊外,其它全部數據塊大小都是同樣的。數據塊的大小和備份因子都是能夠配置的。NameNode負責各個數據塊的備份,DataNode會經過心跳的方式按期的向NameNode發送本身節點上的Block 報告,這個報告中包含了DataNode節點上的全部數據塊的列表。
文件副本的分佈位置直接影響着HDFS的可靠性和性能。一個大型的HDFS文件系統通常都是須要跨不少機架的,不一樣機架之間的數據傳輸須要通過網關,而且,同一個機架中機器之間的帶寬要大於不一樣機架機器之間的帶寬。若是把全部的副本都放在不一樣的機架中,這樣既能夠防止機架失敗致使數據塊不可用,又能夠在讀數據時利用到多個機架的帶寬,而且也能夠很容易的實現負載均衡。可是,若是是寫數據,各個數據塊須要同步到不一樣的機架,會影響到寫數據的效率。
而在Hadoop中,若是副本數量是3的狀況下,Hadoop默認是這麼存放的,把第一個副本放到機架的一個節點上,另外一個副本放到同一個機架的另外一個節點上,把最後一個節點放到不一樣的機架上。這種策略減小了跨機架副本的個數提升了寫的性能,也可以容許一個機架失敗的狀況,算是一個很好的權衡。
關於副本的選擇,在讀的過程當中,HDFS會選擇最近的一個副本給請求者。
關於安全模式,當 Hadoop的NameNode節點啓動時,會進入安全模式階段。在此階段,DataNode會向NameNode上傳它們數據塊的列表,讓 NameNode獲得塊的位置信息,並對每一個文件對應的數據塊副本進行統計。當最小副本條件知足時,即必定比例的數據塊都達到最小副本數,系統就會退出安全模式,而這須要必定的延遲時間。當最小副本條件未達到要求時,就會對副本數不足的數據塊安排DataNode進行復制,直至達到最小副本數。而在安全模式下,系統會處於只讀狀態,NameNode不會處理任何塊的複製和刪除命令。
全部的HDFS中的溝通協議都是基於tcp/ip協議,一個客戶端經過指定的tcp端口與NameNode機器創建鏈接,並經過ClientProtocol協議與NameNode交互。而DataNode則經過DataNode Protocol協議與NameNode進行溝通。HDFS的RCP(遠程過程調用)對ClientProtocol和DataNode Protocol作了封裝。按照HDFS的設計,NameNode不會主動發起任何請求,只會被動接受來自客戶端或DataNode的請求。
能夠容許DataNode失敗。DataNode會按期(默認3秒)的向NameNode發送心跳,若NameNode在指定時間間隔內沒有收到心跳,它就認爲此節點已經失敗。此時,NameNode把失敗節點的數據(從另外的副本節點獲取)備份到另一個健康的節點。這保證了集羣始終維持指定的副本數。
能夠檢測到數據塊損壞。在讀取數據塊時,HDFS會對數據塊和保存的校驗和文件匹配,若是發現不匹配,NameNode一樣會從新備份損壞的數據塊。
瞭解客戶端與NameNode和DataNode的交互過程十分重要,有助於加深咱們對hdfs架構設計的理解。
hdfs有一個FileSystem實例,客戶端經過調用這個實例的open()方法就能夠打開系統中但願讀取的文件。hdfs經過rpc調用NameNode獲取文件塊的位置信息,對於文件的每個塊,NameNode會返回含有該塊副本的DataNode的節點地址,另外,客戶端還會根據網絡拓撲來肯定它與每個DataNode的位置信息,從離它最近的那個DataNode獲取數據塊的副本,最理想的狀況是數據塊就存儲在客戶端所在的節點上。
hdfs會返回一個FSDataInputStream對象,FSDataInputStream類轉而封裝成DFSDataInputStream對象,這個對象管理着與DataNode和NameNode的I/O,具體過程是:
1. 客戶端發起讀請求 2. 客戶端與NameNode獲得文件的塊及位置信息列表 3. 客戶端直接和DataNode交互讀取數據 4. 讀取完成關閉鏈接
當FSDataInputStream與DataNode通訊時遇到錯誤,它會選取另外一個較近的DataNode,併爲出故障的DataNode作標記以避免重複向其讀取數據。FSDataInputStream還會對讀取的數據塊進行校驗和確認,發現塊損壞時也會從新讀取並通知NameNode。
這樣設計的巧妙之處:
在海量數據處理過程當中,主要限制因素是節點之間的帶寬。衡量兩個節點之間的帶寬每每很難實現,在這裏hadoop採起了一個簡單的方法,它把網絡拓撲當作是一棵樹,連個節點的距離=它們到最近共同祖先距離的總和,而樹的層次能夠這麼劃分:
若數據中心d1中一個機架r1中一個節點n1表示爲d1/r1/n1,則:
distance(d1/r1/n1,d1/r1/n1)=0; distance(d1/r1/n1,d1/r1/n2)=2; distance(d1/r1/n1,d1/r2/n3)=4; distance(d1/r1/n1,d2/r3/n4)=6;
hdfs有一個DistributedFileSystem實例,客戶端經過調用這個實例的create()方法就能夠建立文件。DistributedFileSystem會發送給NameNode一個RPC調用,在文件系統的命名空間建立一個新文件,在建立文件前NameNode會作一些檢查,如文件是否存在,客戶端是否有建立權限等,若檢查經過,NameNode會爲建立文件寫一條記錄到本地磁盤的EditLog,若不經過會向客戶端拋出IOException。建立成功以後DistributedFileSystem會返回一個FSDataOutputStream對象,客戶端由此開始寫入數據。
同讀文件過程同樣,FSDataOutputStream類轉而封裝成DFSDataOutputStream對象,這個對象管理着與DataNode和NameNode的I/O,具體過程是:
1. 客戶端在向NameNode請求以前先寫入文件數據到本地文件系統的一個臨時文件 2. 待臨時文件達到塊大小時開始向NameNode請求DataNode信息 3. NameNode在文件系統中建立文件並返回給客戶端一個數據塊及其對應DataNode的地址列表(列表中包含副本存放的地址) 4. 客戶端經過上一步獲得的信息把建立臨時文件塊flush到列表中的第一個DataNode 5. 當文件關閉,NameNode會提交此次文件建立,此時,文件在文件系統中可見
上面第四步描述的flush過程實際處理過程比較負雜,如今單獨描述一下:
1. 首先,第一個DataNode是以數據包(數據包通常4KB)的形式從客戶端接收數據的,DataNode在把數據包寫入到本地磁盤的同時會向第二個DataNode(做爲副本節點)傳送數據。 2. 在第二個DataNode把接收到的數據包寫入本地磁盤時會向第三個DataNode發送數據包 3. 第三個DataNode開始向本地磁盤寫入數據包。此時,數據包以流水線的形式被寫入和備份到全部DataNode節點 4. 傳送管道中的每一個DataNode節點在收到數據後都會向前面那個DataNode發送一個ACK,最終,第一個DataNode會向客戶端發回一個ACK 5. 當客戶端收到數據塊的確認以後,數據塊被認爲已經持久化到全部節點。而後,客戶端會向NameNode發送一個確認 6. 若是管道中的任何一個DataNode失敗,管道會被關閉。數據將會繼續寫到剩餘的DataNode中。同時NameNode會被告知待備份狀態,NameNode會繼續備份數據到新的可用的節點 7. 數據塊都會經過計算校驗和來檢測數據的完整性,校驗和以隱藏文件的形式被單獨存放在hdfs中,供讀取時進行完整性校驗
hdfs文件刪除過程通常須要以下幾步:
原文地址————https://yq.aliyun.com/articles/5905#1. 一開始刪除文件,NameNode只是重命名被刪除的文件到/trash目錄,由於重命名操做只是元信息的變更,因此整個過程很是快。在/trash中文件會被保留必定間隔的時間(可配置,默認是6小時),在這期間,文件能夠很容易的恢復,恢復只須要將文件從/trash移出便可。 2. 當指定的時間到達,NameNode將會把文件從命名空間中刪除 3. 標記刪除的文件塊釋放空間,HDFS文件系統顯示空間增長