Hadoop HDFS 設計隨想

ReyCG發表於2018-12-07

目錄

珍惜時間,時間要花在做有用的事情上,力戒無意義的舉動

——富蘭克林

引言

當資料的大小大於一臺獨立的電腦的儲存能力時,就有必要對它進行分割槽並且儲存在多臺單獨的電腦上。要將非常大的資料集合儲存在多臺電腦上,就會涉及到多臺電腦共享的檔案系統,也就是分散式檔案系統。

分散式檔案系統(distributed file system) 是指管理網路中跨多臺計算機儲存的檔案系統。

分散式檔案系統既然跨多臺電腦,通過網路將它們互聯起來,就可能會出現其中的一個電腦節點連線中斷或者當機的情況,也就是節點故障。在這種情況下也不能出現丟失整個檔案系統任何資料的情況,怎麼來做到呢?先讓我們用發散思維的方式來思考一下。

  1. 將檔案系統的每份資料備份,並且備份不能在同一臺物理計算器上,這樣能保證即使其中一臺計算機當機,檔案系統的整體資料還是完整的
  2. 檔案系統中的資料和檔案資訊(元資訊)是兩個不同的東西,是否要將它們分佈在不同的地方?怎麼能保證檔案資訊(元資訊)的穩定性,在一臺計算機當機後,元資訊不丟失,是否也要引入備份節點的概念?
  3. 既然檔案的資料都比較大,它們的區塊該如何設計?每個區塊是否應該設定的更大一點?
  4. 如果檔案系統資訊與檔案資料分離,假如儲存檔案系統資訊的節點當機該怎麼辦,如何確保分散式檔案系統的高可用性?

這些發散性問題正是 HDFS 設計時要解決的問題,下面就讓我們一起帶著這些問題來看下 HDFS 的解決方案。

HDFS 資料塊的設計

HDFS 是專門為大資料場合設計的分散式檔案系統,要理解 HDFS 資料塊的設計,先要理解大資料場合下超大檔案的特點。所謂超大檔案是指具有幾百 MB,幾百 GB甚至幾百 TB 大小的檔案。這類檔案在大資料中佔有的比重是非常大的。HDFS 資料塊則主要是針對這些超大檔案而設計的。

資料塊應該設定成多大?

HDFS 中預設的塊(block) 大小為 128M,為什麼設計的這麼大呢?

我們知道讀取檔案時主要有兩個時間開銷:

  • 磁碟傳輸時間
  • 定位磁碟塊的時間

如果塊很小的話,一個檔案會有很多磁碟塊組成,光定位磁碟塊就會耗費很多時間。如果將塊的大小設定成 128M,定位磁碟塊就花不了太多時間,主要的時間會花費在傳輸資料上,這樣就很大程度節省了讀取時間。

當然,也不能設計成過大,MapReduce 中的map 任務通常一次只能處理一個塊的時間,任務數太少,作業執行的時間就比較慢了。

抽象成資料塊有哪些好處?

  1. 一個檔案理論上可以無限大

    一個檔案可以由任意個資料塊組成,而且這些資料塊不需要儲存在同一塊磁碟上,由此可以推斷出,一個檔案佔滿整個 Hadoop 叢集的整個磁碟空間。

  2. 檔案資料與檔案元資訊分離,簡化系統設計

  3. 適合資料備份,從而提高資料容錯能力和可用性

    為了保證資料的高可用性,預設會將每個資料塊複製到 3 臺機器上,這樣即使其中一臺機器當機,資料也不會丟失。

    當一臺機器當機後,就會從其他機器上讀取資料,並且採取一定的步驟將當機的機器丟失的資料塊複製到其他的機器上,從而保證副本的數量。

操作塊資訊的命令

fsck 命令可以顯示塊資訊,如列出檔案系統中各個檔案由哪些塊組成的命令

hdfs fsck / -files -blocks

要獲取完整的 hdfs 命令列表,可參考 這裡

HDFS 中節點的設計

有幾種節點型別?

從上節中,我們就看出 HDFS 的檔案資料和檔案元資訊是分離的。由此,HDFS 叢集中的節點會分成兩種型別:

  • namenode 管理節點
    • 對整個檔案系統進行管理
    • 維護檔案系統樹以及其中所有的檔案和目錄
    • 包含所有檔案和目錄的元資訊,記錄每個檔案在各個塊資料節點的資訊
  • datanode 工作節點
    • 受 client 和 namenode 排程會儲存和檢索資料塊

使用者如何訪問 HDFS?

使用者可以通過 client 與 namenode 和 datanode 的互動來訪問整個檔案系統。

使用 Java 客戶端需要使用 maven 引入對應的 jar 包

        <!-- hadoop 部分 begin -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>

此處的 hadoop.version 與 hadoop 版本對應,如

        <hadoop.version>2.6.5</hadoop.version>

如何對 namenode 容錯?

namenode 中儲存的是檔案系統的整體資訊及各個檔案的元資訊。如果它損壞了,就會導致檔案系統上所有的資料就丟失了。因此對 namenode 容錯非常重要, hadoop 提供了兩種機制:

  1. 備份組成檔案系統後設資料持久狀態的檔案

    • 配置讓 namenode 在多個檔案系統上儲存後設資料的資訊
    • 這種操作的特性是實時同步的,而且是原子操作
    • 實現方式就是在將資訊寫入本地磁碟的同時,寫入一個 NFS
  2. 執行一個輔助的 namenode

    注意,這裡的 namenode 並非是備用 (standby) namenode。

    它的作用就是定期合併編輯日誌與名稱空間映象,從而防止編輯日誌過大。並且會儲存合併後的名稱空間映象的副本,並在 namenode 發生故障時使用。

    副作用就是輔助 namenode 儲存的狀態總是滯後於主節點,在主節點全部失效後,難免會丟失部分資料。要解決這個問題,可以將 1 中儲存在 NFS 上的 namenode 後設資料複製到輔助 namenode 作為新的主 namenode 執行。

如何更快的訪問 datanode 中訪問頻繁的塊?

對於 datanode 中訪問頻繁的 block, 就會被顯式快取在 datanode 的記憶體中,以堆外塊快取 (off-heap block cache) 的形式存在。這樣做是為了更快的訪問 datanode ,提高讀操作效能。

使用者或應用通過在快取池(cache pool) 中增加一個 cache directive 告知 namenode 需要快取哪些檔案以及存放多久。cache pool 是一個用來管理快取許可權和資源使用的管理性分組。

如何擴充套件 namenode 以儲存更多的檔案?

由於 namenode 中會在記憶體中儲存檔案系統中的樹資訊和檔案元資訊。當檔案太多時,就會導致檔案系統的資訊容量要大於 namenode 的記憶體限制。這種情況下,就不能再儲存更多的檔案了。因此需要對 namenode 進行橫向擴充套件。 HDFS Federation 聯邦 HDFS 就是用來解決這個問題的。

HDFS 中的高可用性設計

HDFS 在設計時的目標就是要可執行在商用廉價計算機叢集上,而對於大型叢集來說,節點故障率還是非常高的。這也就表示 HDFS 遇到節點故障時,能夠自動處理這些故障,保持叢集的繼續執行,而不會讓使用者察覺到明顯的中斷。也就是 HDFS 的高可用性設計。

在上一節,我們瞭解到 HDFS 中最關鍵的節點就是 namenode,它儲存了整個檔案系統樹以及檔案,目錄的元資訊。如果它出現了 單點失效 SOFP (single point of failure) 的問題,那麼 HDFS 中所有的功能包括 client 都無法執行任何讀取,寫入等操作了。因此, 一個 namenode 節點失效後,如何讓叢集保持繼續執行,而且不會讓使用者察覺到是保證 HDFS 可用性的關鍵。

如何處理 namenode 單點失效問題?

namenode 配置成活動(active)—備用(standy)兩個節點,當活動 namenode 節點失效後,備用 namenode 就會接管它的任務,並繼續處理來自 client 的請求,這些過程對使用者是透明的,並且不會有明顯的中斷。

要實現這個功能,需要在架構上做如下修改:

  • namenode 之間要實現編輯日誌的共享
  • datanode 要同時向兩個 namenode 傳送塊處理報告
  • client 要使用特定的機制來處理 namenode 失效問題,並且這一機制對使用者是透明的
  • 備用 namenode 中包含輔助 namenode 的功能

namenode 間如何共享編輯日誌?

namenode 之間需要通過高可用性共享儲存來共享編輯日誌。

儲存方案有兩種:

  • NFS
  • 群體日誌管理器 QJM(quorum journal manager)。

這裡重點說明下 QJM。QJM 就是為了專門提供高可用性編輯日誌而設計的,被推薦在大多數 HDFS 部署中使用。QJM 是由一組 journal node 節點組成的,典型情況下是 3 個 journal 節點。每次編輯操作時,都會將日誌寫入到大多數節點。

namenode 如何能快速故障切換?

由於 datanode 同時向兩個 namenode 傳送塊處理報告,並且 namenode 會將最新的編輯日誌和資料塊資訊儲存在記憶體中。當活動 namenode 失效後,備用 namenode 能夠在大約幾十秒的時間內就能實現任務接管。這個過程都是由故障轉移控制器(failover controller) 來實現的。

failover controller 故障轉移控制器管理著活動 namenode 轉移為備用 namenode 的轉換過程。預設會使用 zookeeper 來確保有且僅有一個活動 namenode。

每個 namenode 都執行著一個故障轉移控制器,其工作就是通過一個心跳機制,監視 活動 namenode 是否失效,並且在 namenode 失效時自動進行故障切換。除了自動故障轉移外,管理員也可以手動發起故障轉移,將兩個 namenode 節點互換角色。

如何規避非平穩故障轉移?

假設一個 hadoop 叢集中執行著兩個 namenode 節點,節點 A 和 節點 B。此時A 會活動節點,B 為備用節點,兩個節點都正常執行。

在某個時間點,由於網速非常慢或者網路被分割的原因,節點 B 的故障轉移控制器無法通過心跳機制聯絡上節點 A,但此時節點 A 也在正常執行。

在經過幾十秒的時間後,節點 B 就認為節點 A 已經失效,要切換為活動節點,但此時節點 A 也正在活動,這種情況就稱為非平穩故障轉移。

而此時我們要做的就是確保之前的活動節點 A 不再活動(不能同時出現兩個活動節點),這種行為就稱為“規避”。

對於 QJM 共享儲存來說,規避方式就是同一時間 QJM 只允許一個 namenode 像編輯日誌中寫入資料。先前活動的節點訪問 QJM 時, 會設定一個規避命令來殺死 該namenode。

小結

每一種技術實現都是和需求,背景息息相關的。只有理解了需求和背景,針對技術方案的改進看起來才能是那麼的自然和必然。

文末附上根據 《hadoop 權威指南》整理的 HDFS 概念思維導圖,從整體上梳理下HDFS 知識點脈絡。

HDFS concept

參考文件

  1. Hadoop: The Definitive Guide
  2. HDFS Architecture

相關文章