HDFS 架構

簡介

Hadoop 分散式檔案系統 (HDFS) 是一種分散式檔案系統,設計用於執行在商品硬體上。它與現有的分散式檔案系統有許多相似之處。然而,與其他分散式檔案系統的差異卻很顯著。HDFS 具有高度容錯性,而且設計用於部署在低成本硬體上。HDFS 提供對應用程式資料的高傳輸量存取,而且適用於具有大型資料集的應用程式。HDFS 放寬了幾個 POSIX 需求,以啟用對檔案系統資料的串流存取。HDFS 最初是建置為 Apache Nutch 網路搜尋引擎專案的基礎架構。HDFS 是 Apache Hadoop Core 專案的一部分。專案網址為 https://hadoop.dev.org.tw/

假設與目標

硬體故障

硬體故障是常態,而非例外。一個 HDFS 執行個體可能包含數百或數千台伺服器機器,每台機器儲存檔案系統資料的一部分。由於元件數量龐大,而且每個元件都有非零機率會發生故障,這表示 HDFS 的某個元件總是會發生故障。因此,偵測故障並從故障中快速自動復原是 HDFS 的核心架構目標。

串流資料存取

在 HDFS 上執行的應用程式需要串流存取其資料集。它們不是一般用途的應用程式,通常會執行在一般用途的檔案系統上。HDFS 的設計比較偏向批次處理,而非使用者的互動式使用。重點在於資料存取的高傳輸量,而非資料存取的低延遲。POSIX 施加了許多嚴格的需求,而這些需求對於針對 HDFS 的應用程式來說並不需要。在幾個關鍵領域中,POSIX 語意已被捨棄,以增加資料傳輸率。

大型資料集

在 HDFS 上執行的應用程式具有大型資料集。HDFS 中的典型檔案大小為數 GB 到數 TB。因此,HDFS 已調整為支援大型檔案。它應該提供高總計資料頻寬,並擴充到單一叢集中的數百個節點。它應該在單一執行個體中支援數千萬個檔案。

簡單一致性模型

HDFS 應用程式需要一個檔案的寫入一次讀取多次存取模型。一個檔案一旦建立、寫入和關閉,就不需要變更,除了追加和截斷之外。支援將內容追加到檔案結尾,但無法在任意點更新。這個假設簡化了資料一致性問題,並啟用高傳輸量資料存取。MapReduce 應用程式或網路爬蟲應用程式非常符合這個模型。

「移動運算比移動資料便宜」

如果應用程式要求的運算是在其運作資料附近執行,會更有效率。當資料集的規模很大時,這一點尤其正確。這會將網路壅塞降到最低,並增加系統的整體傳輸量。假設通常最好將運算移到資料所在位置附近,而不是將資料移到應用程式執行的所在位置。HDFS 提供介面讓應用程式自行移到資料所在位置附近。

跨異質硬體和軟體平台的可移植性

HDFS 的設計讓它可以輕鬆從一個平台移植到另一個平台。這有助於廣泛採用 HDFS 作為大量應用程式的首選平台。

NameNode 和 DataNodes

HDFS 採用主控/從屬架構。HDFS 群集包含一個 NameNode,此主控伺服器會管理檔案系統命名空間,並規範用戶端對檔案的存取。此外,還有一些 DataNodes,通常群集中的每個節點一個,用於管理執行節點所連接的儲存空間。HDFS 會公開檔案系統命名空間,並允許將使用者資料儲存在檔案中。在內部,檔案會分割成一個或多個區塊,而這些區塊會儲存在一組 DataNodes 中。NameNode 會執行檔案系統命名空間作業,例如開啟、關閉和重新命名檔案和目錄。它也會決定區塊對應到哪些 DataNodes。DataNodes 負責提供檔案系統用戶端的讀取和寫入要求。DataNodes 也會在收到 NameNode 的指示後執行區塊建立、刪除和複製。

HDFS Architecture

NameNode 和 DataNode 是設計用於在商品機器上執行的軟體。這些機器通常執行 GNU/Linux 作業系統 (OS)。HDFS 使用 Java 語言建置;任何支援 Java 的機器都可以執行 NameNode 或 DataNode 軟體。使用高度可攜的 Java 語言表示 HDFS 可以部署在各種機器上。典型的部署有一個專用機器,僅執行 NameNode 軟體。叢集中的其他每部機器執行 DataNode 軟體的一個執行個體。此架構不排除在同一機器上執行多個 DataNode,但在實際部署中很少會這樣做。

叢集中只有一個 NameNode 的存在大幅簡化了系統的架構。NameNode 是所有 HDFS 元資料的仲裁者和儲存庫。系統的設計方式是使用者資料絕不會流經 NameNode。

檔案系統命名空間

HDFS 支援傳統的階層式檔案組織。使用者或應用程式可以在這些目錄中建立目錄和儲存檔案。檔案系統命名空間階層類似於大多數其他現有檔案系統;可以建立和移除檔案、將檔案從一個目錄移到另一個目錄,或重新命名檔案。HDFS 支援 使用者配額存取權限。HDFS 不支援硬連結或軟連結。但是,HDFS 架構不排除實作這些功能。

雖然 HDFS 遵循 檔案系統的命名慣例,但保留了一些路徑和名稱 (例如 /.reserved.snapshot )。透明加密等功能透明加密快照 使用保留路徑。

NameNode 維護檔案系統命名空間。NameNode 會記錄對檔案系統命名空間或其屬性的任何變更。應用程式可以指定 HDFS 應維護的檔案複本數。檔案的複本數稱為該檔案的複製因子。此資訊由 NameNode 儲存。

資料複製

HDFS 的設計目的是在大型叢集中的機器之間可靠地儲存非常大的檔案。它將每個檔案儲存為區塊序列。檔案的區塊會複製以提供容錯能力。區塊大小和複製因子可針對每個檔案設定。

檔案中的所有區塊(最後一個區塊除外)大小相同,而使用者可以在新增變長區塊對附加和 hsync 的支援後,在不將最後一個區塊填滿到設定的區塊大小的情況下,開始新的區塊。

應用程式可以指定檔案的複本數。可以在建立檔案時指定複本係數,並可以在稍後變更。HDFS 中的檔案是寫入一次(追加和截斷除外),並且任何時候只有一個寫入器。

NameNode 會做出所有關於區塊複本的決策。它會定期從叢集中的每個 DataNode 接收心跳和區塊報告。收到心跳表示 DataNode 正常運作。區塊報告包含 DataNode 上所有區塊的清單。

HDFS DataNodes

複本放置:最初步的步驟

複本的放置對 HDFS 的可靠性和效能至關重要。最佳化複本放置讓 HDFS 與大多數其他分散式檔案系統區別開來。這是一個需要大量調整和經驗的功能。機架感知複本放置政策的目的是改善資料可靠性、可用性及網路頻寬使用率。複本放置政策的目前實作是朝此方向所做的初步嘗試。實作此政策的短期目標是在生產系統上驗證此政策、進一步了解其行為,並建立一個基礎來測試和研究更精密的政策。

大型 HDFS 執行個體會在通常跨越許多機架的電腦叢集上執行。不同機架中的兩個節點之間的通訊必須經過交換器。在大部分情況下,相同機架中機器之間的網路頻寬大於不同機架中機器之間的網路頻寬。

NameNode 會透過 Hadoop 機架感知中所述的程序來判斷每個 DataNode 所屬的機架 ID。一個簡單但非最佳化的政策是將複本放置在唯一的機架上。這可以防止在整個機架發生故障時遺失資料,並允許在讀取資料時使用多個機架的頻寬。此政策會在叢集中平均分配複本,這使得在元件故障時容易平衡負載。然而,此政策會增加寫入成本,因為寫入需要將區塊傳輸到多個機架。

對於一般情況,當複製因子為 3 時,HDFS 的配置政策是將一個副本放在本機上(如果寫入器在資料節點上),否則放在與寫入器同一個機架上的隨機資料節點上,另一個副本放在不同(遠端)機架上的節點上,最後一個副本放在同一個遠端機架上的不同節點上。此政策可減少機架間的寫入流量,這通常會改善寫入效能。機架故障的機率遠低於節點故障的機率;此政策不會影響資料可靠性和可用性保證。然而,它並未減少讀取資料時使用的總網路頻寬,因為區塊只會放在兩個唯一的機架上,而不是三個。使用此政策,區塊的副本不會平均分佈在機架上。兩個副本會放在一個機架的不同節點上,而剩餘的副本會放在其他機架的一個節點上。此政策會改善寫入效能,同時不會影響資料可靠性或讀取效能。

如果複製因子大於 3,第 4 個及後續副本的配置會隨機決定,同時將每個機架的副本數量維持在上限以下(基本上為 (replicas - 1) / racks + 2)。

由於 NameNode 不允許資料節點擁有同一個區塊的複數副本,因此建立的最大副本數目為當時的資料節點總數。

在 HDFS 加入對 儲存類型和儲存政策 的支援後,NameNode 會考量政策來配置副本,除了上述的機架感知外。NameNode 會先根據機架感知選擇節點,然後檢查候選節點是否具有與檔案關聯的政策所需的儲存空間。如果候選節點沒有儲存類型,NameNode 會尋找其他節點。如果在第一個路徑中找不到足夠的節點來配置副本,NameNode 會在第二個路徑中尋找具有後備儲存類型的節點。

這裡說明的目前預設副本配置政策仍在進行中。

副本選取

為了將全球頻寬消耗和讀取延遲降至最低,HDFS 會嘗試從最靠近讀取器的複本滿足讀取要求。如果讀取器節點上存在複本,則優先使用該複本滿足讀取要求。如果 HDFS 群集橫跨多個資料中心,則優先使用駐留在本地資料中心的複本,而非任何遠端複本。

區塊放置原則

如上所述,當複製係數為三時,HDFS 的放置原則是:如果寫入器位於資料節點上,則將一個複本放置在本地機器上;否則,將其放置在與寫入器位於同一機架上的隨機資料節點上,將另一個複本放置在不同(遠端)機架上的節點上,並將最後一個複本放置在同一遠端機架上的不同節點上。如果複製係數大於 3,則第 4 個及後續複本的放置會隨機決定,同時將每個機架上的複本數量保持在上限以下(基本上為 (replicas - 1) / racks + 2)。除此之外,HDFS 還支援 4 種不同的可插入式 區塊放置原則。使用者可以根據其基礎架構和使用案例選擇原則。預設情況下,HDFS 支援 BlockPlacementPolicyDefault。

安全模式

在啟動時,NameNode 會進入稱為安全模式的特殊狀態。當 NameNode 處於安全模式狀態時,不會複製資料區塊。NameNode 會從資料節點接收心跳和區塊報告訊息。區塊報告包含資料節點所主機的資料區塊清單。每個區塊都有指定的最小複製數。當該資料區塊的最小複製數已向 NameNode 報到時,該區塊即被視為已安全複製。在可設定的百分比安全複製資料區塊向 NameNode 報到(加上額外的 30 秒)後,NameNode 會退出安全模式狀態。然後,它會確定仍具有少於指定複製數的資料區塊清單(如果有)。然後,NameNode 會將這些區塊複製到其他資料節點。

檔案系統元資料的持久性

HDFS 名稱空間由 NameNode 儲存。NameNode 使用稱為編輯記錄檔的交易記錄來持續記錄發生在檔案系統元資料上的每個變更。例如,在 HDFS 中建立新檔案會導致 NameNode 在編輯記錄檔中插入記錄以指出這一點。類似地,變更檔案的複製係數會導致在編輯記錄檔中插入新記錄。NameNode 使用其本地主機作業系統檔案系統中的檔案來儲存編輯記錄檔。整個檔案系統名稱空間,包括區塊對檔案的對應和檔案系統屬性,都儲存在稱為 FsImage 的檔案中。FsImage 也儲存在 NameNode 的本地檔案系統中作為檔案。

NameNode 會在記憶體中保留整個檔案系統名稱空間和檔案區塊對應表的映像。當 NameNode 啟動或檢查點由可設定的閾值觸發時,它會從磁碟讀取 FsImage 和 EditLog,將 EditLog 中的所有交易套用至 FsImage 的記憶體中表示,並將此新版本刷新到磁碟上的新 FsImage。然後,它可以截斷舊的 EditLog,因為其交易已套用至持久的 FsImage。此程序稱為檢查點。檢查點的目的是確保 HDFS 透過拍攝檔案系統中介資料的快照並將其儲存到 FsImage 中,來取得檔案系統中介資料的一致性檢視。儘管讀取 FsImage 很有效率,但直接對 FsImage 進行增量編輯並非有效率。我們會將編輯內容保留在 Editlog 中,而不是針對每個編輯修改 FsImage。在檢查點期間,會將 Editlog 中的變更套用至 FsImage。檢查點可以在給定的時間間隔(以秒為單位的 dfs.namenode.checkpoint.period)觸發,或在累積給定數量的檔案系統交易後觸發(dfs.namenode.checkpoint.txns)。如果設定這兩個屬性,則會觸發檢查點以達到第一個閾值。

DataNode 會將 HDFS 資料儲存在其本機檔案系統中的檔案中。DataNode 不具備 HDFS 檔案的知識。它會將每個區塊的 HDFS 資料儲存在其本機檔案系統中的個別檔案中。DataNode 不會在同一個目錄中建立所有檔案。相反地,它會使用啟發法來決定每個目錄的最佳檔案數量,並適當地建立子目錄。在同一個目錄中建立所有本機檔案並非最佳做法,因為本機檔案系統可能無法有效支援單一目錄中的大量檔案。當 DataNode 啟動時,它會掃描其本機檔案系統,產生與這些本機檔案對應的所有 HDFS 資料區塊的清單,並將此報告傳送至 NameNode。此報告稱為「區塊報告」。

通訊協定

所有 HDFS 通訊協定都分層在 TCP/IP 協定之上。客戶端會在 NameNode 電腦上建立連線至可設定的 TCP 埠。它會與 NameNode 討論 ClientProtocol。DataNode 會使用 DataNode 協定與 NameNode 討論。遠端程序呼叫 (RPC) 抽象封裝 Client Protocol 和 DataNode Protocol。根據設計,NameNode 永遠不會啟動任何 RPC。相反地,它只會回應 DataNode 或客戶端發出的 RPC 要求。

穩健性

HDFS 的主要目標是即使在發生故障的情況下也能可靠地儲存資料。三種常見的故障類型為 NameNode 故障、DataNode 故障和網路分割。

資料磁碟故障、心跳和重新複製

每個 DataNode 會定期傳送心跳訊息給 NameNode。網路分割可能會導致 DataNode 的子集失去與 NameNode 的連線。NameNode 會透過沒有收到心跳訊息來偵測此狀況。NameNode 會將沒有最近心跳訊息的 DataNode 標記為已死亡,並且不會將任何新的 IO 要求轉送給它們。已註冊到已死亡 DataNode 的任何資料都不再可供 HDFS 使用。DataNode 死亡可能會導致某些區塊的複製因子低於其指定值。NameNode 會持續追蹤哪些區塊需要複製,並在必要時啟動複製。重新複製的需求可能會因為許多原因而產生:DataNode 可能變得不可用、複本可能已損毀、DataNode 上的硬碟可能故障,或者檔案的複製因子可能已增加。

為了避免因 DataNode 的狀態不穩定而導致複製風暴,標記 DataNode 已死亡的逾時時間保守設定為很長(預設超過 10 分鐘)。使用者可以設定較短的間隔來標記 DataNode 為過時,並透過設定來避免在讀取和/或寫入效能敏感的工作負載時使用過時的節點。

叢集重新平衡

HDFS 架構與資料重新平衡方案相容。如果 DataNode 上的可用空間低於某個閾值,方案可能會自動將資料從一個 DataNode 移到另一個 DataNode。在特定檔案突然有大量需求的情況下,方案可能會動態建立其他複本,並重新平衡叢集中的其他資料。這些類型的資料重新平衡方案尚未實作。

資料完整性

從 DataNode 擷取的資料區塊可能已損毀。這種損毀可能是因為儲存裝置故障、網路故障或軟體錯誤而發生。HDFS 軟體會對 HDFS 檔案的內容實作檢查總和。當客戶端建立 HDFS 檔案時,它會計算檔案中每個區塊的總和,並將這些總和儲存在同一個 HDFS 名稱空間中的另一個隱藏檔案中。當客戶端擷取檔案內容時,它會驗證從每個 DataNode 收到的資料是否與儲存在關聯總和檔案中的總和相符。如果不相符,客戶端可以選擇從具有該區塊複本的其他 DataNode 擷取該區塊。

元資料磁碟故障

FsImage 和 EditLog 是 HDFS 的核心資料結構。這些檔案損毀可能會導致 HDFS 執行個體無法運作。因此,可以設定 NameNode 以支援維護 FsImage 和 EditLog 的多個複本。對 FsImage 或 EditLog 的任何更新都會導致每個 FsImage 和 EditLog 同步更新。同步更新 FsImage 和 EditLog 的多個複本可能會降低 NameNode 每秒可支援的名稱空間交易率。不過,這種降低是可以接受的,因為即使 HDFS 應用程式本質上非常資料密集,它們並非元資料密集。當 NameNode 重新啟動時,它會選取最新的相容 FsImage 和 EditLog 來使用。

增加對故障復原力的另一個選項是使用多個 NameNode 啟用高可用性,方法是使用 NFS 上的共用儲存 或使用 分散式編輯記錄(稱為 Journal)。後者是建議的方法。

快照

快照支援儲存特定時間點的資料副本。快照功能的一種用途可能是將已損毀的 HDFS 實例回復到先前已知的良好時間點。

資料組織

資料區塊

HDFS 設計為支援非常大的檔案。與 HDFS 相容的應用程式是那些處理大型資料集的應用程式。這些應用程式只寫入資料一次,但會讀取一次或多次,而且需要以串流速度滿足這些讀取。HDFS 支援檔案的寫入一次讀取多次語意。HDFS 使用的典型區塊大小為 128 MB。因此,HDFS 檔案會切成 128 MB 的區塊,而且如果可能,每個區塊會駐留在不同的資料節點上。

複寫管道處理

當用戶端將資料寫入複寫係數為三的 HDFS 檔案時,NameNode 會使用複寫目標選擇演算法擷取資料節點清單。此清單包含將會儲存該區塊複本的資料節點。然後,用戶端會寫入第一個資料節點。第一個資料節點會開始接收資料的部分,將每個部分寫入其本機儲存庫,並將該部分傳輸到清單中的第二個資料節點。第二個資料節點會開始接收資料區塊的每個部分,將該部分寫入其儲存庫,然後將該部分快取到第三個資料節點。最後,第三個資料節點會將資料寫入其本機儲存庫。因此,資料節點可以從管道中的前一個資料節點接收資料,同時將資料轉發到管道中的下一個資料節點。因此,資料會從一個資料節點傳輸到下一個資料節點。

可存取性

HDFS 可以透過許多不同的方式從應用程式存取。HDFS 原生提供 FileSystem Java API 供應用程式使用。此 Java API 的 C 語言包裝器REST API 也可用。此外,HTTP 瀏覽器也可以用來瀏覽 HDFS 實例的檔案。透過使用 NFS 閘道,HDFS 可以作為用戶端本機檔案系統的一部分進行掛載。

FS Shell

HDFS 允許使用者資料以檔案和目錄的形式組織。它提供一個稱為 FS shell 的命令列介面,讓使用者可以與 HDFS 中的資料互動。此命令集的語法類似於使用者已經熟悉的其他 shell(例如 bash、csh)。以下是幾個範例動作/命令配對

動作 命令
建立一個名為 /foodir 的目錄 bin/hadoop dfs -mkdir /foodir
移除名為 /foodir 的目錄 bin/hadoop fs -rm -R /foodir
檢視名為 /foodir/myfile.txt 的檔案內容 bin/hadoop dfs -cat /foodir/myfile.txt

FS shell 是針對需要使用指令碼語言與儲存資料互動的應用程式。

DFSAdmin

DFSAdmin 指令集用於管理 HDFS 集群。這些指令僅供 HDFS 管理員使用。以下是部分範例動作/指令配對

動作 命令
將叢集設為安全模式 bin/hdfs dfsadmin -safemode enter
產生 DataNodes 清單 bin/hdfs dfsadmin -report
重新委任或解除委任 DataNode(s) bin/hdfs dfsadmin -refreshNodes

瀏覽器介面

典型的 HDFS 安裝會設定一個 Web 伺服器,透過可設定的 TCP 埠公開 HDFS 名稱空間。這使用戶可以瀏覽 HDFS 名稱空間,並使用 Web 瀏覽器檢視其檔案內容。

空間回收

檔案刪除和取消刪除

如果啟用垃圾桶設定,FS Shell 移除的檔案並不會立即從 HDFS 中移除。相反地,HDFS 會將它移至垃圾桶目錄(每個使用者在 /user/<username>/.Trash 下都有自己的垃圾桶目錄)。只要檔案仍留在垃圾桶中,就可以快速還原。

最近刪除的檔案會移至目前的垃圾桶目錄(/user/<username>/.Trash/Current),而在可設定的區間中,HDFS 會為目前垃圾桶目錄中的檔案建立檢查點(在 /user/<username>/.Trash/<date> 下),並在過期時刪除舊檢查點。請參閱FS shell 的 expunge 指令,以了解垃圾桶的檢查點。

在垃圾桶中的使用期限到期後,NameNode 會從 HDFS 名稱空間中刪除檔案。刪除檔案會導致與該檔案相關的區塊被釋放。請注意,使用者刪除檔案與 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。以下註解顯示檔案已移至垃圾桶目錄。

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

現在我們將移除檔案,並使用 skipTrash 選項,這不會將檔案傳送至垃圾桶。它將從 HDFS 中完全移除。

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

現在我們可以看到垃圾桶目錄中只包含檔案 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 呼叫完成與叢集中可用空間出現之間可能會有一段時間延遲。

參考資料

Hadoop JavaDoc API

HDFS 原始碼:https://hadoop.dev.org.tw/version_control.html