首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

分布式系統基礎(一):深度剖析 HDFS/GFS 分布式檔案系統架構與核心機制

     編輯:關於C語言

分布式檔案系統是分布式儲存與計算體系的基石。Google 三大論文(GFS、MapReduce、Bigtable)奠定藍圖,Hadoop 以 Java 開源實現(HDFS、MapReduce、HBase、ZooKeeper)落地生根。本文以統一中文術語,結合 GFS 論文設計哲學與 Hadoop 0.19 原始碼實作,系統剖析分布式檔案系統的架構、核心流程與容錯機制。

術語統一對照表

本文術語HDFS 術語GFS 術語角色說明
主控服務器NameNodeMaster檔案系統大腦:管理目錄樹、分塊對應、DataNode 心跳
數據服務器DataNodeChunkServer存儲實際分塊資料的苦力節點
數據塊BlockChunk檔案切分的基本儲存單元(預設 64MB)
數據包Packet—客戶端寫入時的網路傳輸單元(64KB)
傳輸塊Chunk—Packet 內部的校驗單元(512 Bytes + CRC)
備份主控SecondaryNameNode—定期合併 edits log 產生新 fsimage 的輔助節點

整體架構:單主控、多數據、客戶端庫

  • 主控服務器(NameNode/Master):單點運行,純記憶體儲存目錄樹與分塊映射,持久化僅存 namespace 與 block mapping,分塊位置由 DataNode 心跳動態匯報。避免多主同步開銷,但也成為效能瓶頸與單點故障源。
  • 數據服務器(DataNode/ChunkServer):無狀態苦力,定期心跳(sendHeartbeat)上報容量、區塊列表(blockReport),接收命令(DatanodeCommand)刪除/複製區塊。區塊在本地磁碟以 current/ 目錄樹 + blk_xxx 資料檔 + blk_xxx.meta 中繼檔 儲存。
  • 客戶端(DFSClient):以庫形式嵌入應用,不獨立進程。負責與 NameNode 協商分塊位置,直接與 DataNode 建立資料流連線讀寫。

核心資料結構

NameNode 端

  • FSNamesystem:核心命名空間管理器
  • FSDirectory:目錄樹操作(inode 增刪改查、權限、配額)
  • INodeFile / INodeFileUnderConstruction:檔案元資料,含 BlockInfo[] 陣列記錄分塊資訊與位置
  • EditLog (FSEditLog):操作日誌,支援多檔案同寫保證持久化
  • FSImage:記憶體狀態的定期序列化快照

DataNode 端

  • FSDataset → FSVolumeSet → FSVolume → FSDir:多掛載點、多層級目錄的區塊管理體系
  • DataStorage:支援版本升級/回滾的儲存抽象
  • DataXceiverServer + DataXceiver 執行緒:處理客戶端讀/寫/複製/校驗等 6 類請求

基本檔案操作流程

目錄操作(建立/刪除/重命名/權限/時間)

全由 Client → NameNode (RPC: ClientProtocol) → FSNamesystem → FSDirectory 完成。NameNode 不主動推送指令給 DataNode,而是將待刪除區塊放入 recentInvalidateSets,待 DataNode 心跳時帶走執行——拉取模式降低通訊開銷。

檔案讀取:單一路徑、多區塊串聯

  1. Client 呼叫 getBlockLocations(path, offset, length) 取得 LocatedBlocks
  2. 對每個區塊,從複製品列表選第一個存活 DataNode 連線
  3. DataNode DataXceiver 以 Packet 為單位流式回傳資料
  4. 區塊讀完斷開,銜接下一區塊,直到滿足長度

選址策略:當前實作極簡,僅選第一個存活節點,未考慮機架感知與網路拓撲。

檔案寫入:流水線複製、租約鎖定、校驗恢復

  1. 建立/續寫檔案 → inode 升級為 INodeFileUnderConstruction(持有租約鎖,防併發寫入)
  2. NameNode 分配新區塊,回傳按網路拓撲排序的 DataNode 列表(近者優先)
  3. Client 與首個 DataNode 建立 Socket,發送寫入請求頭,層層轉發建立雙向流水線
  4. Client 將資料緩衝至 64KB Packet → dataQueue → DataStreamer 發送 → 移入 ackQueue 等待應答
  5. DataNode 邊寫本地邊轉發下游,末端回 ack 反向傳遞,Client 收齊 ack 才從 ackQueue 移除
  6. 區塊寫滿 → 向 NameNode 申請新區塊 → 重複上述流程

分布式容錯四大支柱

1. 客戶端故障:租約機制

  • 寫入前向 LeaseManager 申請租約(addLease),DFSClient.LeaseChecker 定期 renewLease
  • NameNode LeaseManager.Monitor 掃描過期租約,強制釋放,避免 INodeFileUnderConstruction 永久佔用

2. DataNode 故障:心跳與區塊報告雙重保障

  • sendHeartbeat:高頻(秒級)上報容量、負載,帶回 DatanodeCommand 執行刪除/複製
  • blockReport:低頻(小時級)全量上報區塊列表,NameNode 比對決定指令
  • 指令緩存機制:blockReport 結果緩存,待下次 heartbeat 統一下發,保證指令可重試

3. NameNode 故障:EditLog + FSImage + SecondaryNameNode

  • 所有元資料變更寫 EditLog(多檔同寫),定期序列化 FSImage
  • 重啟恢復:最新 FSImage + 其後所有 EditLog 重放
  • SecondaryNameNode 定期 doCheckpoint:下載 fsimage + edits → 合併生成新 fsimage → 上傳回 NameNode → 雙端同步
  • 差異:GFS 採同步寫網路日誌(多副本即時一致),HDFS 採批量合併(效率高但有丟失窗口)

4. 資料正確性:CRC 校驗 + Lease Recovery

  • 寫入時:Client 將 Packet 切 512B 傳輸塊,計算 CRC32 附在 Packet 後
  • 流水線末端 DataNode 校驗,失敗觸發 Lease Recovery
  • 恢復算法:選一 Primary DataNode,透過 InterDatanodeProtocol 協調各副本截斷至最短長度——至少一份正確,截斷後必定一致
  • 觸發源:Client 寫入失敗主動發起、或 NameNode 檢測租約過期代理發起

負載均衡與垃圾回收

初始分配:ReplicationTargetChooser

靜態策略:優先滿足客戶端本地寫入速度、副本分散不同機架(容災)、均衡節點負載。

動態調整:Balancer (Tool 獨立進程)

周期性從 NameNode 取得節點使用率,發送 OP_REPLACE_BLOCK 遷移區塊:目標節點拉取資料 → 通知 NameNode 確認 → 刪除來源副本。

垃圾分類處理

  • 正常邏輯產生(檔案刪除、Balancer 遷移):NameNode 直接放入 recentInvalidateSets
  • 異常產生(DataNode 重啟發現舊副本已被替換):DataNode blockReport 時由 NameNode 比對發現
  • 處理方式:心跳攜帶刪除指令,DataNode 直接物理刪除(GFS 延遲刪除支援撤銷,HDFS 判定現場無此需求)

總結與展望

分布式檔案系統的核心矛盾在於單主控元資料管理與多副本資料一致性的協同。HDFS/GFS 通過「租約鎖定寫入順序、流水線複製、CRC 端到端校驗、EditLog/FSImage 斷點恢復、心跳驅動狀態同步」等機制,在商用硬體上構建出高可用、高吞吐的儲存基礎設施。理解這些機制,不僅能用好 Hadoop,更能在設計任何分布式系統時借鑑其核心思想:單點元資料、多點資料、日誌重放、心跳探活、版本向量/租約協調一致性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved