終于有人把HDFS架構和讀寫流程講明白了
一、HDFS基礎
以下是HDFS設計時的目標。
1. 硬件故障
硬件故障對于HDFS來說應該是常態而非例外。HDFS包含數百或數千臺服務器(計算機),每臺都存儲文件系統的一部分數據。事實上,HDFS存在大量組件并且每個組件具有非平凡的故障概率,這意味著某些組件始終不起作用。因此,檢測故障并從中快速自動恢復是HDFS的設計目標。
2. 流式數據訪問
在HDFS上運行的應用程序不是通常在通用文件系統上運行的通用應用程序,需要對其數據集進行流式訪問。HDFS用于批處理而不用于用戶的交互式使用,相對于數據訪問的低延遲更注重數據訪問的高吞吐量。
可移植操作系統接口(Portable Operating System Interface of UNIX, POSIX)標準設置的一些硬性約束對HDFS來說是不需要的,因此HDFS會調整一些POSIX特性來提高數據吞吐率,事實證明是有效的。
3. 超大數據集
在HDFS上運行的應用程序具有大型數據集。HDFS上的一個文件大小一般在吉字節(GB)到太字節(TB)。因此,HDFS需要設計成支持大文件存儲,以提供整體較高的數據傳輸帶寬,能在一個集群里擴展到數百上千個節點。一個HDFS實例需要支撐千萬計的文件。
4. 簡單的一致性模型
HDFS應用需要“一次寫入多次讀取”訪問模型。假設一個文件經過創建、寫入和關閉之后就不會再改變了。這一假設簡化了數據一致性問題,并可實現高吞吐量的數據訪問。MapReduce應用或網絡爬蟲應用都非常適合這個模型。將來還需要擴充這個模型,以便支持文件的附加寫操作。
5. 移動計算而不是移動數據
當應用程序在其操作的數據附近執行時,計算效率更高。當數據集很大時更是如此,這可以最大限度地減少網絡擁塞并提高系統的整體吞吐量。HDFS為應用程序提供了接口,使其自身更靠近數據所在的位置。
6. 跨異構硬件和軟件平臺的可移植性
HDFS的設計考慮到了異構硬件和軟件平臺間的可移植性,方便了HDFS作為大規模數據應用平臺的推廣。
從Hadoop這些年的發展來看,HDFS依靠上述特性,成為不斷演進變革的大數據體系的堅實基石。
二、HDFS架構
HDFS是一個典型的主/備(Master/Slave)架構的分布式系統,由一個名字節點Namenode(Master) +多個數據節點Datanode(Slave)組成。其中Namenode提供元數據服務,Datanode提供數據流服務,用戶通過HDFS客戶端與Namenode和Datanode交互訪問文件系統。
如圖3-1所示HDFS把文件的數據劃分為若干個塊(Block),每個Block存放在一組Datanode上,Namenode負責維護文件到Block的命名空間映射以及每個Block到Datanode的數據塊映射。
▲圖3-1 HDFS架構
HDFS客戶端對文件系統進行操作時,如創建、打開、重命名等,Namenode響應請求并對命名空間進行變更,再返回相關數據塊映射的Datanode,客戶端按照流協議完成數據的讀寫。
- HDFS基本概念
HDFS架構比較簡單,但涉及概念較多,其中幾個重要的概念如下:
1. 塊(Block)
Block是HDFS文件系統處理的最小單位,一個文件可以按照Block大小劃分為多個Block,不同于Linux文件系統中的數據塊,HDFS文件通常是超大文件,因此Block大小一般設置得比較大,默認為128MB。
2. 復制(Replica)
HDFS通過冗余存儲來保證數據的完整性,即一個Block會存放在N個Datanode中,HDFS客戶端向Namenode申請新Block時,Namenode會根據Block分配策略為該Block分配相應的Datanode replica,這些Datanode組成一個流水線(pipeline),數據依次串行寫入,直至Block寫入完成。
3. 名字節點(Namenode)
Namenode是HDFS文件系統的管理節點,主要負責維護文件系統的命名空間(Namespace)或文件目錄樹(Tree)和文件數據塊映射(BlockMap),以及對外提供文件服務。
HDFS文件系統遵循POXIS協議標準,與Linux文件系統類似,采用基于Tree的數據結構,以INode作為節點,實現一個目錄下多個子目錄和文件。INode是一個抽象類,表示File/Directory的層次關系,對于一個文件來說,INodeFile除了包含基本的文件屬性信息,也包含對應的Block信息。
數據塊映射信息則由BlockMap負責管理,在Datanode的心跳上報中,將向Namenode匯報負責存儲的Block列表情況,BlockMap負責維護BlockID到Datanode的映射,以方便文件檢索時快速找到Block對應的HDFS位置。
HDFS每一步操作都以FSEditLog的信息記錄下來,一旦Namenode發生宕機重啟,可以從每一個FSEditLog還原出HDFS操作以恢復整個文件目錄樹,如果HDFS集群發生過很多變更操作,整個過程將相當漫長。
因此HDFS會定期將Namenode的元數據以FSImage的形式寫入文件中,這一操作相當于為HDFS元數據打了一個快照,在恢復時,僅恢復FSImage之后的FSEditLog即可。
由于Namenode在內存中需要存放大量的信息,且恢復過程中集群不可用,HDFS提供HA(主/備Namenode實現故障遷移Failover)以及Federation(多組Namenode提供元數據服務,以掛載表的形式對外提供統一的命名空間)特性以提高穩定性和減少元數據壓力。
4. Datanode
Datanode是HDFS文件系統的數據節點,提供基于Block的本地文件讀寫服務。定期向Namenode發送心跳。Block在本地文件系統中由數據文件及元數據文件組成,前者為數據本身,后者則記錄Block長度和校驗和(checksum)等信息。掃描或讀取數據文件時,HDFS即使運行在廉價的硬件上,也能通過多副本的能力保證數據一致性。
5. FileSystem
HDFS客戶端實現了標準的Hadoop FileSystem接口,向上層應用程序提供了各種各樣的文件操作接口,在內部使用了DFSClient等對象并封裝了較為復雜的交互邏輯,這些邏輯對客戶端都是透明的。
三、HDFS讀寫流程
1. HDFS客戶端寫流程
圖3-2所示為客戶端完成HDFS文件寫入的主流程。
▲圖3-2 客戶端完成HDFS寫入的主流程
1)創建文件并獲得租約
HDFS客戶端通過調用DistributedFileSystem# create來實現遠程調用Namenode提供的創建文件操作,Namenode在指定的路徑下創建一個空的文件并為該客戶端創建一個租約(在續約期內,將只能由這一個客戶端寫數據至該文件),隨后將這個操作記錄至EditLog(編輯日志)。Namenode返回相應的信息后,客戶端將使用這些信息,創建一個標準的Hadoop FSDataOutputStream輸出流對象。
2)寫入數據
HDFS客戶端開始向HdfsData-OutputStream寫入數據,由于當前沒有可寫的Block,DFSOutputStream根據副本數向Namenode申請若干Datanode組成一條流水線來完成數據的寫入,如圖3-3所示。
▲圖3-3 流水線數據寫入示意圖
3)串行寫入數據,直到寫完Block
客戶端的數據以字節(byte)流的形式寫入chunk(以chunk為單位計算checksum(校驗和))。若干個chunk組成packet,數據以packet的形式從客戶端發送到第一個Datanode,再由第一個Datanode發送數據到第二個Datanode并完成本地寫入,以此類推,直到最后一個Datanode寫入本地成功,可以從緩存中移除數據包(packet),如圖3-4所示。
▲圖3-4 串行寫入數據示意圖
4)重復步驟2和步驟3,然后寫數據包和回復數據包,直到數據全部寫完。
5)關閉文件并釋放租約
客戶端執行關閉文件后,HDFS客戶端將會在緩存中的數據被發送完成后遠程調用Namenode執行文件來關閉操作。
Datanode在定期的心跳上報中,以增量的信息匯報最新完成寫入的Block,Namenode則會更新相應的數據塊映射以及在新增Block或關閉文件時根據Block映射副本信息判斷數據是否可視為完全持久化(滿足最小備份因子)。
2. HDFS客戶端讀流程
相對于HDFS文件寫入流程,HDFS讀流程相對簡單,如圖3-5所示。
▲圖3-5 HDFS讀流程
1)HDFS客戶端遠程調用Namenode,查詢元數據信息,獲得這個文件的數據塊位置列表,返回封裝DFSIntputStream的HdfsDataInputStream輸入流對象。
2)客戶端選擇一臺可用Datanode服務器,請求建立輸入流。
3)Datanode向輸入流中寫原始數據和以packet為單位的checksum。
4)客戶端接收數據。如遇到異常,跳轉至步驟2,直到數據全部讀出,而后客戶端關閉輸入流。當客戶端讀取時,可能遇到Datanode或Block異常,導致當前讀取失敗。正由于HDFS的多副本保證,DFSIntputStream將會切換至下一個Datanode進行讀取。與HDFS寫入類似,通過checksum來保證讀取數據的完整性和準確性。
本文摘編自《騰訊大數據構建之道》,經出版方授權發布。(ISBN:978-7-111-71076-9)?