1. 程式人生 > >深入理解Hadoop之HDFS架構

深入理解Hadoop之HDFS架構

Hadoop分散式檔案系統(HDFS)是一種分散式檔案系統。它與現有的分散式檔案系統有許多相似之處。但是,與其他分散式檔案系統的差異是值得我們注意的:

HDFS具有高度容錯能力,旨在部署在低成本硬體上。(高容錯)
HDFS提供對資料的高吞吐量訪問,適用於具有海量資料集的應用程式。(高吞吐量)
HDFS放寬了一些POSIX要求,以實現對檔案系統資料的流式訪問。(流式訪問)

HDFS最初是作為Apache Nutch網路搜尋引擎專案的基礎設施而構建的。HDFS是Apache Hadoop Core專案的一部分。
目標和假設
硬體故障檢測:硬體故障是常態而非例外。Hadoop通常部署在低成本的硬體上,並且通常包含成百上千的伺服器,每個伺服器都儲存檔案系統資料的一部分。由於存在大量的元件,並且每個元件都具有不可忽略(non-trivial )的故障概率,這意味著HDFS的某些元件始終都不起作用。因此,故障檢測並快速恢復是HDFS的核心架構目標。
流式訪問:HDFS更適合批處理而不是互動式使用,更加註重資料訪問的高吞吐量而不是資料訪問的低延遲。在HDFS上執行的應用程式需要對其資料集進行流式訪問。
海量資料集:執行在HDFS上的應用程式具有大型資料集,HDFS中的一個典型檔案的大小是g到tb,因此,HDFS被調優為支援大檔案。它應該提供高聚合資料頻寬,並可擴充套件到單個叢集中的數百個節點。它應該在一個例項中支援數千萬個檔案。
一致性模型:HDFS應用程式需要一個一次寫入多次讀取的檔案訪問模型。檔案一旦建立、寫入和關閉,除了追加和截斷操作外,無需要更改。支援將內容追加到檔案末尾,但無法在任意點更新。該假設簡化了資料一致性問題並實現了高吞吐量資料訪問。MapReduce應用程式或Web爬蟲應用程式完全適合此模型。
移動計算比移動資料便宜:應用程式請求的計算如果在其操作的資料附近執行,效率會高得多。當資料集的大小很大時尤其如此。這可以最大限度地減少網路擁塞並提高系統的整體吞吐量。因此更好的做法是將計算遷移到更靠近資料所在的位置,而不是將資料移動到執行應用程式的位置。HDFS為應用程式提供了一些介面,使它們自己更接近資料所在的位置。
跨平臺和可移植:Hadoop使用Java語言開發,使得Hadoop具有良好的跨平臺性。
NameNode和DataNodes
HDFS具有主/從( master/slave)架構。HDFS叢集由一個NameNode和許多DataNode組成,NameNode是一個主伺服器(master),管理檔案系統名稱空間並管理客端對資料的訪問(NameNode在Hadoop叢集中充當<u>管家</u>的角色)。此外叢集中每個節點通常是一個DataNode,DataNode管理它們的節點上儲存的資料。
HDFS公開檔案系統名稱空間,並允許使用者資料儲存在檔案中。在內部,檔案被分成一個或多個塊(block),這些塊儲存在DataNode中。NameNode執行檔案系統名稱空間的相關操作,如開啟、關閉和重新命名檔案和目錄。它還確定了塊到DataNode的對映(塊儲存到哪個DataNode中)。資料節點負責服務來自檔案系統客戶端的讀寫請求。資料節點還根據NameNode的指令執行塊建立、刪除和複製。
深入理解Hadoop之HDFS架構


叢集中單一NameNode的結構大大簡化了系統的架構。NameNode是所有HDFS元資料的仲裁者和管理者,這樣,使用者資料永遠不會流過NameNode。
檔案系統名稱空間(namespace)
HDFS支援傳統的層次型檔案組織結構。使用者或者應用程式可以建立目錄,然後將檔案儲存在這些目錄裡。檔案系統名稱空間的層次結構和大多數現有的檔案系統類似:使用者可以建立、刪除、移動或重新命名檔案。當前,HDFS不支援使用者磁碟配額和訪問許可權控制,也不支援硬連結和軟連結。但是HDFS架構並不妨礙實現這些特性。
NameNode負責維護檔案系統的名稱空間,任何對檔案系統名稱空間或屬性的修改都將被NameNode記錄下來。應用程式可以設定HDFS儲存的檔案的副本數目。檔案副本的數目稱為檔案的副本系數,這個資訊也是由NameNode儲存的。
如果想深入瞭解HDFS檔案系統名稱空間可以檢視這篇博文:
http://leotse90.com/
...
資料複製
HDFS被設計成能夠在一個大叢集中跨機器可靠地儲存超大檔案。它將每個檔案儲存成一系列的資料塊,除了最後一個,所有的資料塊都是同樣大小的。為了容錯,檔案的所有資料塊都會有副本。每個檔案的資料塊大小和副本系數都是可配置的。應用程式可以指定某個檔案的副本數目。副本系數可以在檔案建立的時候指定,也可以在之後改變。HDFS中的檔案都是一次性寫入的,並且嚴格要求在任何時候只能有一個寫入者。
NameNode全權管理資料塊的複製,它週期性地從叢集中的每個DataNode接收心跳訊號(Heartbeat )和塊狀態報告(Blockreport)。

接收到心跳訊號意味著該DataNode節點工作正常。
塊狀態報告包含了一個該Datanode上所有資料塊的列表。
深入理解Hadoop之HDFS架構


副本存放: 最最開始的一步
副本的存放是HDFS可靠性和效能的關鍵。優化的副本存放策略是HDFS區分於其他大部分分散式檔案系統的重要特性。這種特性需要做大量的調優,並需要經驗的積累。HDFS採用一種稱為機架感知(rack-aware)的策略來改進資料的可靠性、可用性和網路頻寬的利用率。目前實現的副本存放策略只是在這個方向上的第一步。實現這個策略的短期目標是驗證它在生產環境下的有效性,觀察它的行為,為實現更先進的策略打下測試和研究的基礎。
大型HDFS例項一般執行在跨越多個機架的計算機組成的叢集上,不同機架上的兩臺機器之間的通訊需要經過交換機。在大多數情況下,同一個機架內的兩臺機器間的頻寬會比不同機架的兩臺機器間的頻寬大。
通過一個機架感知的過程,NameNode可以確定每個DataNode所屬的機架id。一個簡單但沒有優化的策略就是將副本存放在不同的機架上。這樣可以有效防止當整個機架失效時資料的丟失,並且允許讀資料的時候充分利用多個機架的頻寬。這種策略設定可以將副本均勻分佈在叢集中,有利於當元件失效情況下的負載均衡。但是,因為這種策略的一個寫操作需要傳輸資料塊到多個機架,這增加了寫的代價。
在大多數情況下,副本系數是3,HDFS的存放策略是將一個副本存放在本地機架的節點上,一個副本放在同一機架的另一個節點上,最後一個副本放在不同機架的節點上。這種策略減少了機架間的資料傳輸,這就提高了寫操作的效率。機架的錯誤遠遠比節點的錯誤少,所以這個策略不會影響到資料的可靠性和可用性。於此同時,因為資料塊只放在兩個(不是三個)不同的機架上,所以此策略減少了讀取資料時需要的網路傳輸總頻寬。在這種策略下,副本並不是均勻分佈在不同的機架上。三分之一的副本在一個節點上,三分之二的副本在一個機架上,其他副本均勻分佈在剩下的機架中,這一策略在不損害資料可靠性和讀取效能的情況下改進了寫的效能。
副本選擇
為了降低整體的頻寬消耗和讀取延時,HDFS會盡量讓讀取程式讀取離它最近的副本。如果在讀取程式的同一個機架上有一個副本,那麼就讀取該副本。如果一個HDFS叢集跨越多個數據中心,那麼客戶端也將首先讀本地資料中心的副本。(就近原則)
安全模式
NameNode啟動後會進入一個稱為安全模式的特殊狀態。處於安全模式的NameNode是不會進行資料塊的複製的。NameNode從所有的 DataNode接收心跳訊號和塊狀態報告。塊狀態報告包括了某個DataNode所有的資料塊列表。每個資料塊都有一個指定的最小副本數。當NameNode檢測確認某個資料塊的副本數目達到這個最小值,那麼該資料塊就會被認為是副本安全(safely replicated)的;在一定百分比(這個引數可配置)的資料塊被NameNode檢測確認是安全之後(加上一個額外的30秒等待時間),NameNode將退出安全模式狀態。接下來它會確定還有哪些資料塊的副本沒有達到指定數目,並將這些資料塊複製到其他DataNode上。
檔案系統元資料的持久化
NameNode上儲存著HDFS的DataNode空間。對於任何對檔案系統元資料產生修改的操作,NameNode都會使用一種稱為EditLog的事務日誌記錄下來。例如,在HDFS中建立一個檔案,NameNode就會在Editlog中插入一條記錄來表示;同樣地,修改檔案的副本系數也將往Editlog插入一條記錄。NameNode在本地作業系統的檔案系統中儲存這個Editlog。整個檔案系統的DataNode空間,包括資料塊到檔案的對映、檔案的屬性等,都儲存在一個稱為FsImage的檔案中,這個檔案也是放在NameNode所在的本地檔案系統上。
NameNode在記憶體中儲存著整個檔案系統的DataNode空間和檔案資料塊對映(Blockmap)的映像。這個關鍵的元資料結構設計得很緊湊,因而一個有4G記憶體的NameNode足夠支撐大量的檔案和目錄。當NameNode啟動時,它從硬碟中讀取Editlog和FsImage,將所有Editlog中的事務作用在記憶體中的FsImage上,並將這個新版本的FsImage從記憶體中儲存到本地磁碟上,然後刪除舊的Editlog,因為這個舊的Editlog的事務都已經作用在FsImage上了。這個過程稱為一個檢查點(checkpoint)。在當前實現中,檢查點只發生在NameNode啟動時,在不久的將來將實現支援週期性的檢查點。
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的架構支援資料均衡策略。如果某個Datanode節點上的空閒空間低於特定的臨界點,按照均衡策略系統就會自動地將資料從這個Datanode移動到其他空閒的Datanode。當對某個檔案的請求突然增加,那麼也可能啟動一個計劃建立該檔案新的副本,並且同時重新平衡叢集中的其他資料。這些均衡策略目前還沒有實現。
資料完整性
從某個Datanode獲取的資料塊有可能是損壞的,損壞可能是由Datanode的儲存裝置錯誤、網路錯誤或者軟體bug造成的。HDFS客戶端軟體實現了對HDFS檔案內容的校驗和(checksum)檢查。當客戶端建立一個新的HDFS檔案,會計算這個檔案每個資料塊的校驗和,並將校驗和作為一個單獨的隱藏檔案儲存在同一個HDFSDataNode空間下。當客戶端獲取檔案內容後,它會檢驗從Datanode獲取的資料跟相應的校驗和檔案中的校驗和是否匹配,如果不匹配,客戶端可以選擇從其他Datanode獲取該資料塊的副本。
元資料磁碟錯誤
FsImage和Editlog是HDFS的核心資料結構。如果這些檔案損壞了,整個HDFS例項都將失效。因而,NameNode可以配置成支援維護多個FsImage和Editlog的副本。任何對FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操作可能會降低NameNode每秒處理的DataNode空間事務數量。然而這個代價是可以接受的,因為即使HDFS的應用是資料密集的,它們也非元資料密集的。當NameNode重啟的時候,它會選取最近的完整的FsImage和Editlog來使用。
增加故障恢復能力的另一個選擇是使用多個NameNode 在NFS上使用共享儲存或使用分散式編輯日誌(稱為Journal)來啟用高可用性。後者是推薦的方法。
快照
快照支援在特定時刻儲存資料副本。快照功能的一種用途可以是將損壞的HDFS例項回滾到先前已知的良好時間點。
資料組織
資料塊
HDFS被設計成支援大檔案,適用HDFS的是那些需要處理大規模的資料集的應用。這些應用都是隻寫入資料一次,但卻讀取一次或多次,並且讀取速度應能滿足流式讀取的需要。HDFS支援檔案的“一次寫入多次讀取”語義。一個典型的資料塊大小是128MB。因而,HDFS中的檔案總是按照128M被切分成不同的塊,每個塊儘可能地儲存於不同的Datanode中。
流水線複製
當客戶端向HDFS檔案寫入資料的時候,一開始是寫到本地臨時檔案中。假設該檔案的副本系數設定為3,當本地臨時檔案累積到一個數據塊的大小時,客戶端會從NameNode獲取一個Datanode列表用於存放副本。然後客戶端開始向第一個Datanode傳輸資料,第一個Datanode一小部分一小部分(4 KB)地接收資料,將每一部分寫入本地倉庫,並同時傳輸該部分到列表中第二個Datanode節點。第二個Datanode也是這樣,一小部分一小部分地接收資料,寫入本地倉庫,並同時傳給第三個Datanode。最後,第三個Datanode接收資料並存儲在本地。因此,Datanode能流水線式地從前一個節點接收資料,並在同時轉發給下一個節點,資料以流水線的方式從前一個Datanode複製到下一個。
可訪問性
可以通過多種不同方式從應用程式訪問HDFS。本地,HDFS 為應用程式提供了FileSystem Java API。一本Java API的C語言包裝和REST API也是可用的。此外,還有HTTP瀏覽器,也可用於瀏覽HDFS例項的檔案。通過使用NFS閘道器,HDFS可以作為客戶端本地檔案系統的一部分進行安裝。
FS Shell
HDFS以檔案和目錄的形式組織使用者資料。它提供了一個命令列的介面(FS Shell)讓使用者與HDFS中的資料進行互動。命令的語法和使用者熟悉的其他shell(例如 bash, csh)工具類似。下面是一些動作/命令的示例:
深入理解Hadoop之HDFS架構
FS shell適用於需要指令碼語言與儲存資料互動的應用程式。

DFSAdmin
典型的HDFS安裝配置Web伺服器以通過可配置的TCP埠公開HDFS名稱空間。這允許使用者使用Web瀏覽器導航HDFS名稱空間並檢視其檔案的內容。
深入理解Hadoop之HDFS架構
儲存空間回收
檔案的刪除和恢復
如果啟用了回收站配置,當用戶或應用程式刪除某個檔案時,這個檔案並沒有立刻從HDFS中刪除。實際上,HDFS會將這個檔案重新命名轉移到/trash目錄(/user/<username>/.Trash)。只要檔案還在/trash目錄中,該檔案就可以被迅速地恢復。檔案在/trash中儲存的時間是可配置的,當超過這個時間時,NameNode就會將該檔案從DataNode空間中刪除。刪除檔案會使得該檔案相關的資料塊被釋放。注意,從使用者刪除檔案到HDFS空閒空間的增加之間會有一定時間的延遲。
以下是一個示例,它將顯示FS Shell如何從HDFS中刪除檔案。我們在目錄delete下建立了2個檔案(test1和test2)

$ hadoop fs -mkdir -p delete/test1
$ hadoop fs -mkdir -p delete/test2
$ hadoop fs -ls delete/
Found 2 items
drwxr-xr-x   - hadoop hadoop          0 2015-05-08 12:39 delete/test1
drwxr-xr-x   - hadoop hadoop          0 2015-05-08 12:40 delete/test2

我們將刪除檔案test1。下面的註釋顯示該檔案已移至/trash目錄。

$ hadoop fs -rm -r delete/test1
Moved: hdfs://localhost:8020/user/hadoop/delete/test1 to trash at: hdfs://localhost:8020/user/hadoop/.Trash/Current

現在我們將使用skipTrash選項刪除該檔案,該選項不會將檔案傳送到Trash。它將從HDFS中完全刪除。

$ hadoop fs -rm -r -skipTrash delete/test2
Deleted delete/test2

我們現在可以看到Trash目錄只包含檔案test1。

$ hadoop fs -ls .Trash/Current/user/hadoop/delete/
Found 1 items\
drwxr-xr-x   - hadoop hadoop          0 2015-05-08 12:39 .Trash/Current/user/hadoop/delete/test1

因此檔案test1進入垃圾箱並永久刪除檔案test2。
減少副本系數
當一個檔案的副本系數被減小後,NameNode會選擇過剩的副本刪除。下次心跳檢測時會將該資訊傳遞給Datanode。Datanode遂即移除相應的資料塊,叢集中的空閒空間加大。同樣,在呼叫setReplication API結束和叢集中空閒空間增加間會有一定的延遲。