1. 程式人生 > 其它 >HDFS 內部工作機制

HDFS 內部工作機制

  • HDFS叢集分為兩大角色:NameNode、DataNode (Secondary Namenode)

  • NameNode 負責管理整個檔案系統的元資料

  • DataNode 負責管理使用者的檔案塊(Block)

  • 檔案會按照固定的大小(預設 128 M)切成若干檔案塊(Block)後分布式儲存在若干臺 DataNode 伺服器上

  • 每一個檔案塊可以有多個副本,並存放在不同的 DataNode 伺服器上

  • DataNode 會定期向 NameNode 彙報自身所儲存的檔案塊(Block)資訊,而 NameNode 則會負責保持檔案的副本數量

HDFS 的內部工作機制對客戶端保持透明,客戶端通過向 NameNode 傳送請求來訪問 HDFS 存放的檔案

HDFS 寫資料流程

# 上傳 file.data 到 HDFS (300M)
hadoop fs -put file.data /data/file.data
流程圖
詳細步驟
  1. 使用客戶端命令列向 HDFS 上傳 file.data(300M)檔案時,客戶端會向叢集中的 NameNode 通訊請求上傳檔案到 HDFS 目錄樹的 /data/file.data 路徑
  2. NameNode 收到客戶端請求後會檢查 /data 目錄 和 /data/file.data 檔案是否存在,如果不存在則向客戶端返回可以進行上傳檔案
  3. 由於上傳的 file.data 檔案是 300M(預設檔案資料塊 128M),檔案需要被切分成三個檔案資料庫(Block)依次進行上傳。客戶端先向 NameNode 請求上傳第一個檔案資料塊(Block)以及告訴 NameNode 存放檔案資料塊的副本數量(預設 3 個),NameNode 則會返回 3 個可以上傳的 DataNode(假設是 DataNode1、DataNode2、DataNode4)
  4. 客戶端選擇與 DataNode1 建立網路連線,而 DataNode1 接著與 DataNode2 建立網路連線,DataNode2 與DataNode4 建立網路連線,(本質就是 RPC 遠端呼叫形成 pipeline 網路連線鏈路通路)。通道建立完畢後,DataNode1 會向客戶端作出應答,告訴客戶端可以上傳第一個檔案資料塊(Block)
  5. 客戶端收到 DataNode1 的應答後,以 packet 包為單位向 DataNode1 上傳資料流,上傳的資料流是先存放到 DataNode1 的一個緩衝區,再緩衝區同時向其他 DataNode 緩衝區傳,緩衝區再寫到磁碟
  6. 上傳過程中,DataNode 會進行校驗,校驗失敗則傳輸失敗,但是隻要有一個 DataNode 傳輸成功即可。因為 NameNode 會判斷成功的數量與備份要求的是否一致,不一致的話則會對資料進行同步使得一致。
  7. 第一個檔案資料塊(Block)上傳完成後,會再重新與 NameNode 建立網路連線,請求上傳第二個檔案資料塊(Block),即重複第3步流程,直到所有檔案資料快(Block)全部上傳為止。
副本放置策略 - 就近原則

挑選 DataNode 主要考慮空間與距離因素

  • 第一個副本考慮選擇與客戶端距離最近的 DataNode(同機架)
  • 第二個副本考慮跨機架選擇一個 DataNode(增加副本的可靠性)
  • 第三個副本挑選與第一個 DataNode 同機架的 DataNode(配置機架感知)

為了最小化全域性頻寬消耗和讀取延遲,HDFS 試圖滿足來自離客戶端最近的副本的讀取請求。如果在與客戶端相同的機架上存在一個副本,則首選該副本來滿足讀請求。如果 HDFS 叢集跨越多個數據中心,那麼駐留在本地資料中心的副本優於任何遠端副本。

NameNode 安全模式(SafeMode)

  • 在啟動 NameNode 時,NameNode 進入一個稱為 安全模式(SafeMode)的特殊狀態。當 NameNode 處於該狀態,不會發生檔案資料塊的複製。
  • NameNode 從資料節點接收心跳和 BlockReport 訊息。Blockreport包含DataNode託管的資料塊列表。每個塊都有一個指定的最小副本數量。當該資料塊的最小副本數量(dfs.namenode.replication.min =1)已與
    NameNode 簽入時,就認為該塊是安全複製的。當安全複製的資料塊的可配置百分比(
    dfs.namenode.safemode.threshold-pct =0.999f)通過NameNode(加上額外的30秒)檢查後,
    NameNode將退出安全模式狀態。然後,它確定仍然少於指定副本數量的資料塊列表(如果有的話)。然後
    NameNode將這些塊複製到其他資料節點。

安全模式(Safemode )開啟時不能有寫操作

安全模式(SafeMode)命令:

客戶端寫資料 DataNode 故障處理
  • 客戶端在寫入檔案資料塊到 DataNode 發生故障時,客戶端會關閉與 DataNode 之間的網路通訊 pipeline 管線,以確保故障節點 pipeline 管線下游的 DataNode 不會漏掉 packet 資料包
  • 客戶端將故障 DataNode 通知給 NameNode,以便故障的 DataNode 在恢復後可以刪除儲存的部分資料塊
  • 客戶端基於另外兩個正常的 DataNode 構建一條新的 pipeline 管線,將剩下的檔案資料塊寫入 pipeline 管線中正常的 DataNode
  • 當 NameNode 注意到檔案資料塊副本數量不足的時候,就會在另一個 DataNode 節點上建立一個新的副本,後續的資料塊則繼續正常處理

HDFS 讀資料流程

# 從 HDFS 下載 /data/file.data(300M) 檔案到本地系統
hadoop fs -get /data/file.data ./
詳細步驟
  1. 使用客戶端命令列從 HDFS 下載 /data/file.data(300M)檔案時,客戶端與 NameNode 建立網路連線,並請求要下載的檔案;NameNode 檢視元資料,找到下載檔案被切割的 3 個檔案資料塊(Block)所存放的 DataNode 資訊,並返回給客戶端
  2. 客戶端首先下載第一個檔案資料塊(Block),而第一個檔案資料塊(Block)在 3 個 DataNode 上都有其副本,客戶端根據就近原則去挑選一個 DataNode 建立網路連線,並請求讀取檔案資料塊(Block);DataNode 讀取磁碟資料流,向客戶端傳送資料流
  3. 客戶端接收 DataNode 傳送的資料流並暫存快取中,然後寫入到本地檔案中,接著客戶端重複步驟1、2 來下載第二個檔案資料塊(Block)(和第三個檔案資料塊(Block),然後資料以追加的形式寫入到檔案中,最終合併成一個完成的檔案
客戶端讀資料 DataNode 故障處理
  • 客戶端在 DataNode 上讀取檔案資料塊(Block)時發生故障(即客戶端 與 DataNode 無法正常通訊),客戶端會試圖從故障 DataNode 最鄰近的一個儲存副本的 DataNode 讀取檔案資料塊(Block)
  • 客戶端會記錄故障的 DataNode,以確保以後不會反覆讀取該故障 DataNode 節點上後續的檔案資料塊(Block)
  • 客戶端會通過校驗和確認從 DataNode 讀取的資料是否完整,如果發現有損壞的檔案資料塊(Block),客戶端會試圖從其他儲存有副本的 DataNode 讀取資料,並將被損壞的塊通知給 NameNode
  • NameNode 記錄有損壞的檔案資料塊的 DataNode,通知其刪除資料,並建立新的檔案資料塊的副本,以確保副本數量的一致

NameNode 工作機制

NameNode 職責

  • 負責客戶端請求的響應
  • 管理元資料(即 HDFS 的目錄結構及每一個檔案的檔案資料塊(Block)資訊(如 block id、block 副本數量,block 的存放位置等)
  • 容錯處理

NameNode 管理元資料

元資料的儲存
  • 記憶體元資料

    NameNode 在記憶體(meta data)中儲存著一份實時、完整的元資料

  • 磁碟元資料映象檔案

    NameNode 在磁碟中儲存著某個時間點元資料在記憶體中的映象 fsimage 檔案(類似 redis 的 RDB)

    • fsimage 包含 Hadoop 檔案系統中的所有目錄和檔案 idnode 的序列化資訊(具體而言,檔案包含的資訊有修改時間、訪問時間、塊大小和組成一個檔案塊資訊等,目錄包含的資訊有修改時間、訪問控制權限等)
    • fsimage 並不包含 DataNode 的資訊,而是包含 DataNode 上檔案資料塊(Block)的對映資訊。
    • 當一個新的 DataNode 加入到叢集中,DataNode 會向 NameNode 提供檔案資料塊(Block)的資訊,而 NameNode 會定期向 DataNode 的索取檔案資料塊的資訊,以使得 NameNode 擁有最新的檔案資料塊(Block)對映資訊
    • 由於 fsimage 包含 Hadoop 檔案系統中的所有目錄和檔案 idnode 的序列化資訊,所以如果 fsimage 檔案丟失或損壞,那麼即使 DataNode 上有檔案資料塊(Block),也無法從 DataNode 上的獲取資料
  • 資料操作日誌檔案

    NameNode 會把引起元資料變化的客戶端操作記錄在 edits 日誌檔案中(類似 redis 的 AOF)

元資料目錄
  • 在第一次部署好 Hadoop 叢集的時候,需要在 NameNode 節點上格式化磁碟

    [root@node-01 etc]# hadoop namenode -format
    
  • 格式化完成之後,將會在 NameNode 儲存路徑的 current 目錄下建立元資料目錄

    current/
    |-- VERSION
    |-- edits_*
    |-- fsimage_*
    |-- fsimage_*.md5
    |-- seen_txid
    
    • VERSION

      namespaceID=1064465530
      clusterID=CID-a1afedaf-49ed-4219-bae3-7b7268fca624
      cTime=1616685687133
      storageType=NAME_NODE
      blockpoolID=BP-593175008-192.168.229.21-1616685687133
      layoutVersion=-65
      
      • namespaceID:是檔案系統的唯一識別符號,在檔案系統首次格式化之後生成的
      • clusterID:是系統生成或手動指定的叢集 ID
      • cTime:NameNode 儲存時間的建立時間
      • storageType:說明這個檔案儲存的是什麼程序的資料結構資訊
      • layoutVersion:HDFS 永久性資料結構的版本資訊
      • blockpoolID:針對每一個 Namespace 所對應的 blockpool 的 ID(DataNode Block 目錄名)
    • seen_txid

      該檔案中記錄的是 edits 日誌滾動的序號,每次重啟NameNode時,NameNode就知道要將會執行edits_0000001~ edits_seen_txid 的 edits 日誌檔案,已更新記憶體元資料

    • edits_* 檢視器(OEV)

      oev 是 offline edits viewer(離線 edits 檢視器)的縮寫,該工具可以使用 oev 工具檢視 edits 日誌檔案和 fsimage 映象檔案內容

      命令格式:hdfs oev -p 檔案型別 -i 編輯日誌 -o 轉換後文件輸出路徑

      • -p –processor 指定輸出處理器: binary (二進位制格式), xml (預設,XML格式),stats
      • -i –inputFile 輸入edits檔案(如果是xml字尾,表示XML格式,其他表示二進位制)
      • -o –outputFile 輸出檔案,如果存在,則會覆蓋
      [root@node-01 current]# hdfs oev -i edits_inprogress_0000000000000000081 -o edits.xml
      
    • images_* 檢視器(OIV)

      oiv 是 offline image viewer 的縮寫,用於將 fsimage 檔案的內容轉儲到指定檔案裡以便於閱讀。OIV 在處理很大的 fsimage 檔案時是相當快。

      命令格式:hdfs oiv -p 檔案型別 -i 編輯日誌 -o 轉換後文件輸出路徑

      • -p –processor 指定輸出處理器: LS、XML、FileDistribution
      • -i –inputFile 輸入 fsimage 檔案(如果是xml字尾,表示XML格式,其他表示二進位制)
      • -o –outputFile 輸出檔案(如果存在,則會覆蓋)
      [root@node-01 current]# hdfs oiv -i fsimage_0000000000000000080 -p XML -o fsimage.xml
      
元資料的記憶體載入
  1. NameNode 啟動時,會將磁碟中 fsimage 檔案中的內容載入到記憶體中,之後再執行資料操作日誌 edits 檔案,使得記憶體獲得一份最新最完整的元資料
  2. NameNode 啟動後,客戶端的所有更新資料操作會同步寫入到 edits 日誌中(fsimage 檔案一般很大,直接寫入會導致系統執行緩慢)

元資料的 CheckPoint(檢查點)機制

  • Secondary NameNode 會定期從 NameNode 上下載 fsimage 映象和新生成的 edits 日誌,然後載入 fsimage 映象到記憶體中,接著順序解析 edits 檔案,對記憶體中的元資料物件進行修改整合

  • 整合完成後,將記憶體元資料序列化成一個新的 fsimage 映象檔案,並將這個 fsimage 映象檔案上傳給 NameNode

  • NameNode 接收到 Secondary NameNode 傳送的新 fsimage 映象檔案後,即可將舊的 fsimage 映象檔案和 edist 日誌替換掉

    注1:Secondary NameNode 每次做 CheckPoint 操作時,第一次 CheckPoint 需要下載 fsimage 映象檔案,以後就不用下載,因為之前已經下載過了

    注2:Namenode 和 Secondary NameNode 的工作目錄儲存結構完全相同,當 NameNode 故障退出需要重新恢復時,可以從 Secondary NameNode 的工作目錄中將 fsimage 拷貝到 NameNode 的工作目錄,以恢復NameNode 的元資料

CheckPoint(檢查點)操作觸發條件相關配置

CheckPoint(檢查點)相關配置 hdfs-size.xml 如下:

  • Secondary NameNode 檢查觸發條件是否滿足的頻率配置(預設 60 s)

    <property>
            <name>dfs.namenode.checkpoint.check.period</name>
            <value>60</value>
    </property>
    
  • Secondary NameNode 程序啟動位置的配置

    <property>        <name>dfs.namenode.secondary.http-address</name>        <value>node-02:9868</value></property>
    
  • Secondary NameNode 儲存元資料檔案的目錄配置

    <property>        <name>dfs.namenode.checkpoint.dir</name>        <value> /root/apps/hadoop-3.2.1/data/namesecondary</value>  </property>
    
  • Secondary NameNode 最多重試次數(預設3次)

    <property>        <name>dfs.namenode.checkpoint.max-retries</name>        <value>3</value></property>
    
  • Secondary NameNode 兩次 CheckPoint 之間間隔時長(預設 1 小時)

    <property>        <name>dfs.namenode.checkpoint.period</name>        <value>3600</value></property>
    

DataNode 工作機制

  • DataNode 儲存管理使用者的檔案資料塊(Block),一個檔案資料塊(Block)在 DataNode 上以檔案形式儲存在磁碟上
  • DataNode 定期向 NameNode 彙報自身所持有的所有檔案資料塊(Block)資訊(彙報間隔時間由配置項 dfs.blockreport.intervalMsec 決定)
  • 心跳檢測預設每 3 秒檢測一次(檢測間隔時間由配置項 dfs.heartbeat.interval 決定),心跳檢測返回結果帶有 NameNode 給 DataNode 的命令(如複製檔案資料塊副本到另一個 DataNode 或刪除某個損壞的檔案資料塊)
  • 如果超過限定時間沒有收到某個 DataNode 的心跳,NameNode 則認為該 DataNode 不可用
  • DataNode 掉線後會觸發副本檢查機制,NameNode 會在叢集內通知正常的 DataNode 進行副本複製
  • Hadoop 叢集執行中可以安全加入和退出一些 DataNode 節點
DataNode 職責
  • 儲存管理使用者的檔案資料塊(Block)

    • 資料:使用者的檔案資料塊(Block)

    • 元資料:檔案資料塊(Block)長度、檔案資料塊校驗和、時間戳等

  • 定期向 NameNode 彙報自身所持有的檔案資料塊(Block)資訊(通過心跳資訊上報)

    <!-- 設定 datanode 向 namenode 報告 block 資訊的時間間隔(預設6小時)<property>	<name>dfs.blockreport.intervalMsec</name>	<value>21600000</value>	<description>Determines block reporting interval in milliseconds.</description></property>
    
DataNode 掉線時限引數設定

DateNode 以固定週期向 NameNode 傳送心跳,NameNode 如果一段時間內沒有收到心跳,就會標記 DateNode 為故障宕機,這段時間叫做 DataNode 超時時長。

timeout = rtbeat.recheck.interval + 10 * dfs.heartbeat.interval

  • DataNode 核查心跳間隔時長(預設 5 分鐘)
<property>	<name>dfs.namenode.heartbeat.recheck-interval</name>	<value>300000</value>	<description>This time decides the interval to check for expired datanodes. With this value and 		dfs.heartbeat.interval, the interval of deciding the datanode is stale or not is also 		        calculated.The unit of this configuration is millisecond.    </description></property>
  • DataNode 心跳檢測間隔時長(預設 3 秒)
<property>	<name>dfs.heartbeat.interval</name>	<value>3</value>	<description>Determines datanode heartbeat interval in seconds. Can use the following suffix 			(case insensitive): ms(millis), s(sec), m(min), h(hour), d(day) to specify the time (such as 		2s, 2m, 1h, etc.). Or provide complete number in seconds (such as 30 for 30 seconds).	</description></property>
DataNode 目錄結構

與 NameNode 不同,DataNode 儲存目錄是初始階段自動建立的,不需要額外的格式化

  • VERSION(datanode/current/)

    [root@node-01 data]# cat datanode/current/VERSIONstorageID=DS-89dfa113-a168-4eed-87c5-c25d024e49e0clusterID=CID-a1afedaf-49ed-4219-bae3-7b7268fca624cTime=0datanodeUuid=a39bf511-8b1f-4da8-8c1f-3c4201be87cdstorageType=DATA_NODElayoutVersion=-57
    
    • storageID:磁碟儲存 ID
    • clusterID:叢集 ID (全域性唯一)
    • cTime:標記 DataNode 儲存系統的建立時間,對於剛格式化的儲存系統屬性值為 0
    • datanodeUuid:datanode 的唯一識別碼
    • storageType:儲存型別
    • layoutVersion:是一個負數(通常只有 HDFS 增加新特性才會更新這個版本號)
  • VERSION(datanode/current/BP-593175008-192.168.229.21-1616685687133/current)

    [root@node-01 data]# cat datanode/current/BP-593175008-192.168.229.21-1616685687133/current/VERSIONnamespaceID=1064465530cTime=1616685687133blockpoolID=BP-593175008-192.168.229.21-1616685687133layoutVersion=-57
    
    • namespaceID:DataNode 首次訪問 NameNode 時從 NameNode 獲取的 storageID(對每個 DataNode 是唯一的,但對單個 DataNode 中所有儲存目錄則是相同的),NameNode 可用這個屬性來區別不同的 DataNode
    • cTime:標記 DataNode 儲存系統的建立時間
    • blockpoolID:一個 block pool id 用於標識一個 block pool,並且是跨叢集的全域性唯一
    • layoutVersion:一個負整數,通常只有 HDFS 增加新特性才會更新版本號