卷1:第8章 HDFS——Hadoop分布式文件系統(tǒng)

2018-02-24 15:55 更新

Hadoop分布式文件系統(tǒng)(HDFS)的設計主旨,在于對超大規(guī)模數(shù)據(jù)集提供可靠的存儲功能,并對用戶應用程序提供高帶寬的輸入輸出數(shù)據(jù)流。在大型的集群里,上千臺服務器均可直接參與到數(shù)據(jù)存儲和應用程序任務執(zhí)行。通過多服務器,分布式的存儲和計算,計算資源的規(guī)模能夠按照需要增長,并兼顧在各種規(guī)模上經(jīng)濟適用性。 本文主要描述了HDFS的架構,并以Yahoo!企業(yè)數(shù)據(jù)服務為例,介紹了如何使用HDFS系統(tǒng)管理高達4O PB規(guī)模的數(shù)據(jù)庫的經(jīng)驗。
8.1 介紹

Hadoop采用MapReduce范式[DG04]進行設計,提供了一套分布式文件系統(tǒng)和框架,用以對超大規(guī)模的數(shù)據(jù)集進行分析和變換。HDFS的接口沿襲了Unix文件系統(tǒng)的設計模式,但在其基礎上做出了改進,以提高在實際應用中的訪問性能。

Hapoop所具有一個重要特點,就是把數(shù)據(jù)和運算分開,并將二者分布存放在數(shù)以千計的服務器主機上,應用程序計算以及相關數(shù)據(jù)都以并行方式處理。一個Hadoop集群可以僅僅通過增加普通服務器的方式,來擴展其運算、存儲和I/O帶寬的規(guī)模。Yahoo所使用的Hadoop集群組,共包含40,000臺服務器,存儲并處理多達40 PB(1 Petabytes = 1000000000000000 字節(jié))的應用數(shù)據(jù),其中最大的單個集群,使用多達4000個服務器。此外,在世界范圍內,還有100多家其他的組織和機構表示,他們也使用Hadoop來進行數(shù)據(jù)存儲和處理。

HDFS將文件系統(tǒng)元數(shù)據(jù)(File System Metadata)和應用數(shù)據(jù)(Application Data)分離存放。與其他種類的分布式文件系統(tǒng)類似,例如PVFS[CIRT00], Lustre2, 以及GFS[GGL03],HDFS將元數(shù)據(jù)存放在專用服務器上,該服務器稱為“NameNode”(名稱節(jié)點);應用數(shù)據(jù)被存放在其他的服務器上,這些服務器稱為“DataNode”(數(shù)據(jù)節(jié)點)。在該分布式系統(tǒng)中,各個服務器之間均通過網(wǎng)絡連接,確保節(jié)點之間可以通過基于TCP族的協(xié)議進行相互通信。HDFS不像Lustre或者PVFS,它并不依賴于數(shù)據(jù)保護機制(例如RAID)來確保數(shù)據(jù)的穩(wěn)定性,而是像GFS那樣,在多個DataNode節(jié)點上保存數(shù)據(jù)的多個副本,以此來確保數(shù)據(jù)的穩(wěn)定。采用這樣的策略,其好處不僅僅在于數(shù)據(jù)安全方面,在數(shù)據(jù)傳輸帶寬方面,由于一個數(shù)據(jù)有多個副本,因此可以通過多線程訪問倍速提高帶寬(就像迅雷下載的原理一樣——譯者注),并且采用此種方式還可以提高從較近的服務器節(jié)點上獲取數(shù)據(jù)的幾率。
8.2 架構
8.2.1 NameNode(名稱節(jié)點)
HDFS命名空間采用層次化(樹狀——譯者注)的結構存放文件和目錄。文件和目錄用NameNode上的inodes表示。Inode記錄了權限,修改和訪問時間,命名空間,磁盤容量等屬性。文件內容會被分成不同的“大塊”(典型分塊策略是每塊128M,不過用戶可以對每個文件的分塊大小進行選擇)。NameNode負責維護命名空間樹以及與DataNode上文件分塊的映射關系。目前采用的設計結構是,沒一個集群只有一個NameNode,一個NameNode可以對應多個DataNode以及成千上萬的HDFS客戶端。一個DataNode可以同步執(zhí)行多個應用任務。
8.2.2 映像和日志
Inode和定義metadata的系統(tǒng)文件塊列表統(tǒng)稱為Image(映像). NameNode將整個命名空間映像保存在RAM中。而映像的持久化記錄則保存在NameNode的本地文件系統(tǒng)中,該持久化記錄被稱為Checkpoint(檢查點)。NameNode還會記錄HDFS中寫入的操作,并將其存入一個記錄文件,存放在本地文件系統(tǒng)中,這個記錄文件被叫做Journal(日志)。存放塊位置的副本不屬于持久化檢查點(persistent checkpoint)的一個部分。 每個客戶端發(fā)起的事務都會被記錄到日志里,然后日志文件會被刷新和同步,再發(fā)送回客戶端。NameNode上的檢查點文件(Checkpoint file)一旦生成,就不允許再修改。如果NameNode重啟,在系統(tǒng)管理員的要求下,或者根據(jù)CheckpointNode的定義(下章介紹),可以生成一個新的文件記錄checkpoint。 在啟動過程中,NameNode會從checkpoint中初始化命名空間映像,然后根據(jù)日志重現(xiàn)所有的寫入更改操作。在NameNode開始響應客戶端之前,一個新的checkpoint和一個空的日志將被保存到存儲目錄當中。
為了提高持久性,系統(tǒng)會將checkpoint文件和日志的多個冗余備份存儲到多個獨立的本地卷以及遠程NFS服務器上。之所以存儲到獨立卷標,是為了避免單個卷標失效后造成文件丟失;存儲到遠程服務器則是為了預防整個節(jié)點崩潰后造成所有本地文件丟失。如果NameNode遇到了錯誤,無法將日志信息寫入到某個存儲目錄,那么系統(tǒng)就會自動將該有問題的目錄排除到存儲目錄列表的范圍之外。如果NameNode發(fā)現(xiàn)連一個可用的存儲目錄都找不到,則會執(zhí)行自動關閉操作(節(jié)點失效)。
NameNode是一個多線程的系統(tǒng)應用,可以同時處理多個客戶端的申請。不過,將事務存儲到磁盤是一個較大的性能瓶頸,因為如果有一個線程正在存儲中,其他線程都必須等待該線程完成其刷新和同步過程完成后,才能繼續(xù)進行操作。為了優(yōu)化這一過程,NameNode采用將多個事務批處理的方式,當某個NameNode線程初始化了一個刷新同步操作時,所有的事務會被一次性批處理,然后一起提交。其他的線程只需要檢查他們的事務是否被存儲了即可,而不需要再去提交刷新同步操作。
8.2.3 數(shù)據(jù)節(jié)點
DataNode上的每一個塊(block)副本都由兩個本地文件系統(tǒng)上的文件共同表示。其中一個文件包含了塊(block)本身所需包含的數(shù)據(jù),另一個文件則記錄了該塊的元數(shù)據(jù),包括塊所含數(shù)據(jù)大小和文件生成時間戳。數(shù)據(jù)文件的大小等于該塊(block)的真實大小,而不是像傳統(tǒng)的文件系統(tǒng)一樣,需要用額外的存儲空間湊成完整的塊。因此,如果一個塊里只需要一半的空間存儲數(shù)據(jù),那么就只需要在本地系統(tǒng)上分配半塊的存儲空間即可。
在啟動過程中,每個DataNode通過“握手”的方式與另外一個NameNode節(jié)點連接。之所以采用“握手”方式,是為了驗證DataNode的命名空間ID以及軟件的版本號。如果一個節(jié)點的ID或者版本號不匹配,那么DataNode節(jié)點就會自動關閉。
命名空間ID是在文件系統(tǒng)實例格式化的時候就分配好的。命名空間ID被在集群內的所有節(jié)點上都有持久化存儲。由于不同命名空間ID的節(jié)點無法加入到集群中,因此能夠保證集群文件系統(tǒng)的統(tǒng)一性。一個DataNode在剛初始化的時候沒有命名空間ID,此時該節(jié)點被允許加入集群,一旦加入,該節(jié)點就會以加入的集群的ID作為自己的ID。
“握手”之后,DataNode被注冊到NameNode。DataNode持久化保存其唯一的存儲ID(storage ID)。存儲ID是一個DataNode的內部標識符,該標識符能夠確保即使是服務器用不同的IP地址或者端口啟動,仍然可以被識別。存儲ID在DataNode首次注冊到NameNode時即被分配,一旦分配后便無法更改。
DataNode采用發(fā)送“塊報告”(block report)的形式,向NameNode標識其所包含的塊副本。塊報告包含了塊ID,生成時間戳,以及每個塊副本的長度等等。 首個塊報告會在DataNode注冊后立即發(fā)送。隨后的塊報告會每小時發(fā)送一次,以確保NameNode能夠知道集群中塊副本的最新情況。
在正常情況下,DataNode想NameNode發(fā)送“心跳信號”,以確認DataNode運行正常,以及其所包含的塊數(shù)據(jù)可用。默認的“心跳信號”的時間間隔是3秒。如果NameNode長達10分鐘沒有接受到來自于DataNode的心跳信號,那么久會認為為該DataNode節(jié)點已經(jīng)失效,其所包含的塊(block)已經(jīng)無法使用。接下來NameNode就會計劃在其他的DataNode上創(chuàng)建新的塊數(shù)據(jù)。
來自DataNode的心跳信號也會附帶包括總存儲容量,存儲使用量,當前數(shù)據(jù)傳輸進度等附加信息。這些統(tǒng)計數(shù)據(jù)可用于NameNode塊分配,以及作為負載均衡決策的參考。
NameNode不能直接向DataNode發(fā)送請求。它只通過回復心跳信號的方式來向DataNode發(fā)送指令。指令的內容包括,將塊移到其他節(jié)點,移除本地塊副本,重新注冊和發(fā)送即時塊報告,關閉當前節(jié)點等等。
這些命令對于維護整個系統(tǒng)的完整性來說非常關鍵,因此即使是在超大集群上,保持心跳信號的頻率也是至關重要的。NameNode每秒能夠處理上千條心跳信號,并且不影響到NameNode的其他正常操作。
8.2.4 HDFS客戶端
用戶應用程序通過HDFS客戶端連接到HDFS文件系統(tǒng),通過庫文件可導出HDFS文件系統(tǒng)的接口。
像很多傳統(tǒng)的文件系統(tǒng)一樣,HDFS支持文件的讀、寫和刪除操作,還支持對目錄的創(chuàng)建和刪除操作。用戶通過帶命名空間的路徑對文件和目錄進行引用。用戶程序不需要知道文件系統(tǒng)的元數(shù)據(jù)和具體存儲在哪個服務器上,也不需要關心一個塊有多少個副本。
當一個應用程序讀一個文件的時候,HDFS客戶端首先向NameNode索要包含該文件的文件塊的DataNode節(jié)點的列表。該列表會按照網(wǎng)絡拓撲距離的遠近進行排序。然后客戶端會直接與相應的DataNode節(jié)點進行聯(lián)系,要求傳輸所需的文件塊。當客戶端寫一個文件的時候,它會首先要求NameNode選擇一個DataNode,該DataNode需要包含所寫入的文件的首個文件塊。接下來,客戶端會搭建一個從節(jié)點到節(jié)點的通信管道,用以進行數(shù)據(jù)傳輸。當?shù)谝粋€塊被寫入后,客戶端會申新的DataNode,用以寫入下一個塊。此時,新的通信管線建立,客戶端會通過管線寫入更多的數(shù)據(jù)。每個文件塊所寫入的DataNode節(jié)點也許會完全不同??蛻舳?,NameNode和DataNode之間的關系如圖8.1所示。
圖8.1 HDFS客戶端創(chuàng)建新文件

與傳統(tǒng)的文件系統(tǒng)不同的是,HDFS提供一個API用以暴露文件塊的位置。這個功能允許應用程序,例如MapReduce框架,去數(shù)據(jù)所存放的地點進行任務調度,以此來提高讀數(shù)據(jù)的新能。API也允許一個應用程序設定文件的復制因子。默認情況下,文件的復制因子是3,。對于關鍵的文件或者使用頻率較多的文件,使用更高的復制因子,能夠提高容錯性,以及提升文件的訪問帶寬。
8.2.5 檢查點節(jié)點
HDFS中的NameNode節(jié)點,除了其主要職責是相應客戶端請求以外,還能夠有選擇地扮演一到兩個其他的角色,例如做檢查點節(jié)點或者備份節(jié)點。該角色是在節(jié)點啟動的時候特有的。
檢查點節(jié)點定期地域已經(jīng)存在的檢查點和日志一起,創(chuàng)建新的檢查點和空日志。檢查點節(jié)點通常運行于一個非NameNode節(jié)點的主機上,但它和NameNode節(jié)點擁有相同的內存需求配置。檢查點節(jié)點從NameNode上下載當前的檢查點和日志文件,將其在本地進行合并,并將新的檢查點返回到NameNode.
創(chuàng)建一個定期檢查點是保護文件系統(tǒng)元數(shù)據(jù)的一種方式。如果命名空間映像中的所有其他持久化拷貝均無法使用,系統(tǒng)還能夠從最近一次的checkpoint文件中啟動。當創(chuàng)建一個新的checkpoint被更新到NameNode的時候,還能讓NameNode產(chǎn)生截斷日志的效果。HDFS集群組可以長時間持續(xù)運行,無需重啟,但這也導致了系統(tǒng)日志的大小會不斷增長。當系統(tǒng)日志大到一定程度的時候,日志文件丟失或者損壞的幾率就會增加。所以,一個日志太大的節(jié)點需要重啟一下來對日志文件進行更新(截斷)。對于一個較大的集群來說,平均處理一周的日志內容需要耗費一小時的時間。所以較好的頻率是,每天創(chuàng)建一次新日志。

8.2.6 備份節(jié)點
HDFS的備份節(jié)點是最近在加入系統(tǒng)的一項特色功能。就像CheckpintNode一樣,備份節(jié)點能夠定期創(chuàng)建檢查點,但是不同的是,備份節(jié)點一直保存在內存中,隨著文件系統(tǒng)命名空間的映像更新和不斷更新,并與NameNode的狀態(tài)隨時保持同步。
備份節(jié)點從活動的NameNode節(jié)點中接受命名空間事務的日志流,并將它們以日志的形式存儲在其自身所帶的存儲目錄里,并使用自身的內存和命名空間映像來執(zhí)行這個事務。NameNodez則將BackupNode當做日志一樣看待,就仿佛是存儲在其自身的存儲目錄里一樣。如果NameNode失效,那么BackupNode節(jié)點內存中的映像和磁盤上的checkpoint文件就可以作為最近的命名空間狀態(tài)的備份,以備還原。
BackupNode能夠動態(tài)創(chuàng)建一個checkpoint,而不需要從活動的NameNode上下載其checkpoint文件和日志文件。因為BackupNode始終把最新的狀態(tài)保存在它自身命名空間的內存中。這一特性使得在BackupNode節(jié)點上處理checkpoint變得非常高效,因為只需要把命名空間存儲到本地服務器就可以了,而不需要和NameNode再進行交互。
BackupNode還可以被看做是一個只讀的NameNode. 它包含了除文件塊位置以外的所有文件系統(tǒng)的元數(shù)據(jù)信息。除了修改命名空間或者文件塊位置以外,BackupNode可以做NameNode所能做的所有操作。使用BackupNode能夠使NameNode在運行的時候不進行持久化存儲,從而把持久化命名空間狀態(tài)的任務挪到BackupNode節(jié)點上進行。
8.2.7 系統(tǒng)更新和文件系統(tǒng)快照
在軟件更新的過程中,由于軟件的bug或者人為操作的失誤,文件系統(tǒng)損壞的幾率會隨之提升。在HDFS中創(chuàng)建系統(tǒng)快照的目的,就在于把系統(tǒng)升級過程中可能對數(shù)據(jù)造成的隱患降到最低。
快照機制讓系統(tǒng)管理員將當前系統(tǒng)狀態(tài)持久化到文件系統(tǒng)中,這樣以來,如果系統(tǒng)升級后出現(xiàn)了數(shù)據(jù)丟失或者損壞,便有機會進行回滾操作,將HDFS的命名空間和存儲狀態(tài)恢復到系統(tǒng)快照進行的時刻。
系統(tǒng)快照(只能有一個)在系統(tǒng)啟動后,根據(jù)集群管理員的選擇可隨時生成。如果要求生成一個系統(tǒng)快照,NameNode首先會讀取checkpoint和日志文件,并將其在內存中合并。然后,NameNode在新的位置創(chuàng)建并寫入一個新的checkpoint和空的日志,保證舊的Checkpoint和日志不會被改變。
在進行“握手”方式通信時,NameNode指示DataNode是否要創(chuàng)建一個本地的系統(tǒng)快照。DataNode上的本地系統(tǒng)快照不會復制本地的存儲目錄中包含的數(shù)據(jù)信息,因為如果這么做的話,會使得每個集群上的DataNode上的數(shù)據(jù)占據(jù)雙倍的存儲空間。因此,取而代之的策略是,建立一份目錄結構的副本,并用“鏈接”的方式將已經(jīng)存在的塊文件指向到目錄副本。當DataNode嘗試移除一個文件塊時,只需要移除鏈接就可以了,在文件塊增量時,也是使用copy-on-wirte技術。所以舊的塊副本在其原先的目錄結構中保持不變。
集群管理員可以選擇在重啟系統(tǒng)時,將HDFS回滾到快照所表示的狀態(tài)。NameNode在快照恢復時,會恢復所記錄的checkpoint。DataNode則會恢復之前被更名的文件目錄,并初始化一個幕后進程,用以刪除在snapshot創(chuàng)建之后系統(tǒng)新增的文件塊副本。選擇回滾后,回滾之前的操作將無法再繼續(xù)(無法前滾)。集群管理員可以下達放棄快照的指令,來恢復被快照功能所占用的存儲權。如果再系統(tǒng)升級期間進行快照,那么升級過程將被終止。
隨著系統(tǒng)的升級,NameNode的checkpoint文件和日志文件的格式可能會發(fā)生變化,或者塊文件的數(shù)據(jù)結構也可能發(fā)生改變。因此,系統(tǒng)中使用“設計版本號”(layout version)來標識數(shù)據(jù)表現(xiàn)格式,該版本號被持久化地存儲在NameNode以及DataNode的存儲目錄中。每個節(jié)點在啟動時,會將其系統(tǒng)設計版本號和存儲目錄中的設計版本號進行對比,并自動嘗試將舊的數(shù)據(jù)格式轉換到新的版本。為了實現(xiàn)系統(tǒng)版本升級,新版本重啟時會強制創(chuàng)建系統(tǒng)快照。
8.3 文件 I/O 操作和復制管理
當然,一個文件系統(tǒng)的根本任務是用來存儲數(shù)據(jù)和文件。如果要理解HDFS如何完成這一基本任務,我們就必須從它如何進行數(shù)據(jù)的讀寫,以及文件塊如何管理這兩方面來說明。
8.3.1 文件讀寫
應用程序通過創(chuàng)建新文件以及向新文件寫數(shù)據(jù)的方式,給HDFS系統(tǒng)添加數(shù)據(jù)。文件關閉以后,被寫入的數(shù)據(jù)就無法再修改或者刪除,只有以“追加”方式重新打開文件后,才能再次為文件添加數(shù)據(jù)。HDFS采用單線程寫,多線程讀的模式。
HDFS客戶端需要首先獲得對文件操作的授權,然后才能對文件進行寫操作。在此期間,其他的客戶端都不能對該文件進行寫操作。被授權的客戶端通過向NameNode發(fā)送心跳信號來定期更新授權的狀態(tài)。當文件關閉時,授權會被回收。文件授權期限分為軟限制期和硬限制期兩個等級。當處于軟限制期內時,寫文件的客戶端獨占對文件的訪問權。當軟限制過期后,如果客戶端無法關閉文件,或沒有釋放對文件的授權,其他客戶端即可以預定獲取授權。當硬限制期過期后(一小時左右),如果此時客戶端還沒有更新(釋放)授權,HDFS會認為原客戶端已經(jīng)退出,并自動終止文件的寫行為,收回文件控制授權。文件的寫控制授權并不會阻止其他客戶端對文件進行讀操作。因此一個文件可以有多個并行的客戶端對其進行讀取。
HDFS文件由多個文件塊組成。當需要創(chuàng)建一個新文件塊時,NameNode會生成唯一的塊ID,分配塊空間,以及決定將塊和塊的備份副本存儲到哪些DataNode節(jié)點上。DataNode節(jié)點會形成一個管道,管道中DataNode節(jié)點的順序能夠確保從客戶端到上一DataNode節(jié)點的總體網(wǎng)絡距離最小。文件的則以有序包(sequence of packets)的形式被推送到管道。應用程序客戶端創(chuàng)建第一個緩沖區(qū),并向其中寫入字節(jié)。第一個緩沖區(qū)被填滿后(一般是64 KB大?。?,數(shù)據(jù)會被推送到管道。后續(xù)的包隨時可以推送,并不需要等前一個包發(fā)送成功并發(fā)回通知(這被稱為“未答復發(fā)送”——譯者注)。不過,這種未答復發(fā)送包的數(shù)目會根據(jù)客戶端所限定的“未答復包窗口”(outstanding packets windows)的大小進行限制。
在數(shù)據(jù)寫入HDFS文件后,只要文件寫操作沒有關閉,HDFS就不保證數(shù)據(jù)在此期間對新增的客戶端讀操作可見。如果客戶端用戶程序需要確保對寫入數(shù)據(jù)的可見性,可以顯示地執(zhí)行hflush操作。這樣,當前的包就會被立即推送到管道,并且hflush操作會一直等到所有管道中的DataNode返回成功接收到數(shù)據(jù)的通知后才會停止。如此就可以保證所有在執(zhí)行hflush之前所寫入的數(shù)據(jù)對試圖讀取的客戶端用戶均可見。

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號