博客 / 詳情

返回

【Hadoop】HDFS架構解析

一、HDFS簡介

HDFS(Hadoop Distributed File System)是一個分佈式文件系統,它的主要設計目標是為了解決‌存儲和處理大規模數據的挑戰‌,尤其針對‌低成本硬件集羣‌和‌高吞吐量批處理‌場景。其有以下幾個主要特性:

  1. 跨平台(底層由Java開發,天然支持跨平台部署)
  2. 高容錯(數據冗餘存儲,數據塊默認有3個副本)
  3. 高吞吐(並行讀取或寫入多個數據塊,且是順序讀寫,流式數據訪問)
  4. 橫向拓展(NameNode只管理元數據,實際數據由DataNode分佈式存儲)

但HDFS也有一些侷限性,比如以下幾個點

  1. 小文件性能差(小文件如果非常多,其元數據會佔用大量空間)
  2. 不支持文件修改(只能順序追加)

所以HDFS更適用於大規模數據存儲以及離線批處理場景

二、系統架構

HDFS採用的是Master/Slave主從架構,由一個NameNode和多個DataNode節點組成,架構示意圖如下:
image.png

NameNode(管理節點):是HDFS的重要組成部分,管理整個HDFS集羣,主要有以下幾個作用:

  1. 元數據管理:維護文件命名空間和數據塊之間的映射關係(比如/logs/a.log這個文件,需要維護這個文件分為哪幾個數據塊,每個數據塊在哪個DataNode節點上,對應的副本又在哪個DataNode節點上)
  2. 客户端協調:客户端讀寫文件時,都會先與NameNode節點進行通信,拿到協調結果後再跟實際的DataNode進行通信(後面會詳細介紹客户端讀寫過程)
  3. DataNode故障處理:DataNode定時向NameNode發送心跳,如果檢測心跳超時,則標記DataNode失效,觸發副本複製,保持副本數量一致

DataNode(數據節點):是實際存儲數據的節點,主要有以下幾個作用

  1. 數據塊存儲:每個文件都會被切分成一個個數據塊Block(默認128M),而DataNode負責實際存儲這些數據塊及其副本(比如數據塊副本數為3,則3個DataNode節點上各存儲一個該數據塊的副本)
  2. 心跳與狀態彙報:DataNode每隔一定的週期(默認3秒)向NameNode發送心跳,並且定期向NameNode彙報本地存儲的數據塊列表
  3. 數據讀寫操作:與客户端進行交互,響應客户端與其他DataNode的數據塊讀寫請求

SecondaryNameNode(SNN):NameNode的輔助,定期地將edits文件合併到fsimage文件(這個操作叫checkpoint),避免edits文件過大,影響NameNode啓動恢復時間

三、NameNode持久化設計

NameNode會將元數據全量存儲到內存中,這樣可以快速響應客户端請求,但內存並不會永久保留,所以NameNode對元數據進行了持久化設計(快照+操作日誌,與Zookeeper設計思想基本一致),保證元數據的持久化。持久化的關鍵在於兩個文件,fsimage快照文件 和 edits操作日誌文件,存放的路徑在NameNode的 ${dfs.namenode.name.dir}/current 目錄下,如下圖
image.png

edits操作日誌

edits文件是增量操作日誌文件,會記錄所有對元數據的修改操作(比如創建/刪除文件、修改權限等)。

生成機制:NameNode會實時將元數據操作追加到edits文件中,並更新內存中的元數據,並且當edits文件達到閾值(默認64M),滾動生成一個新的edits文件

fsimage快照文件

fsimage文件是某一時刻HDFS的元數據全量快照文件,記錄了完整目錄結構、文件權限、數據塊分配信息等。所以當前HDFS的全量元數據 = 最新fsimage + edits

生成機制:SecondaryNameNode會定期(默認1小時)將fsimage和edits日誌合併,生成新的fsimage快照

快照合併步驟

  1. SecondaryNameNode 請求NameNode停止使用當前edits文件,也就是上圖裏圈紅的edits_inprogress文件,生成新edits.new繼續記錄操作
  2. SecondaryNameNode下載fsimage和舊edits文件到本地,將fsimage文件反序列化到內存中,並重放舊edits文件,得到全量元數據
  3. 將內存中的全量元數據序列化生成fsimage文件,並上傳給NameNode

啓動恢復

NameNode加載最新的fsimage快照到內存中,並重放edits_inprogress文件,將元數據更新到最新狀態(與上面SecondaryNameNode合併過程中的操作是一致的)

四、客户端讀寫流程

客户端讀取文件

image.png

  1. 客户端向NameNode請求文件的元數據(比如數據塊位置,副本信息)
  2. NameNode返回文件對應的數據塊列表Block IDs以及每個數據塊分別對應哪個DataNode
  3. 客户端拿到數據塊信息,與對應的DataNode建立連接,並請求數據塊
  4. DataNode返回數據塊
  5. 客户端驗證數據塊的CRC32校驗和,保證數據完整性,並按邏輯順序將多個數據塊拼接為完整文件
  6. 關閉與DataNode的連接

客户端寫入文件

image.png

  1. 客户端向NameNode發起文件寫入請求
  2. NameNode為文件第一個數據塊分配寫入通道(假設有個DataNode節點,副本為3,那麼通道可以是DN1 -> DN3 -> DN5)
  3. 客户端與DN1建立連接
  4. 開始鏈式傳輸第一個數據塊,傳輸鏈路:客户端 -> DN1 -> DN3 -> DN5(客户端不直接與DN3、DN5建立連接)
  5. 每個DataNode接受完數據塊之後,會向上一個DataNode節點返回ACK,直到DN1返回ACK給客户端
  6. 客户端向NameNode提交該數據塊,表示該數據塊已完成寫入
  7. 重複2-6步驟,提交所有數據塊後,通知NameNode整個文件已完成寫入
  8. NameNode更新該文件的元數據信息

五、總結

HDFS作為Hadoop生態的存儲基石,提供了統一、可靠、可拓展的底層存儲,支持多種數據格式(如文本、parquet、orc等),與MapReduce、Hive、Spark、Flink等計算框架深度融合,最近幾年lakehouse(湖倉一體)架構開始慢慢走進大家的視野,HDFS或對象存儲也可以作為數據湖的底層存儲,所以HDFS在大數據領域扮演着非常重要的角色。

user avatar laoqing 頭像 u_16213607 頭像
2 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.