HDFS 原理、架構與特性介紹
本文主要講述 HDFS原理-架構、副本機制、HDFS負載均衡、機架感知、健壯性、文件刪除恢復機制
1:當前HDFS架構詳盡分析

</span>
HDFS架構
?NameNode?DataNode
?Sencondary NameNode
</span>
數據存儲細節

NameNode 目錄結構
Namenode 的目錄結構:${ dfs.name.dir}/current /VERSION
/edits
/fsimage
/fstime
dfs.name.dir 是 hdfs-site.xml 里配置的若干個目錄組成的列表。
NameNode
Namenode 上保存著 HDFS 的名字空間。對于任何對文件系統元數據產生修改的操作, Namenode 都會使用一種稱為 EditLog 的事務日志記錄下來。例如,在 HDFS 中創建一個文件, Namenode 就會在 Editlog 中插入一條記錄來表示;同樣地,修改文件的副本系數也將往 Editlog 插入一條記錄。 Namenode 在本地操作系統的文件系統中存儲這個 Editlog 。整個文件系統的名 字空間,包括數據塊到文件的映射、文件的屬性等,都存儲在一個稱為 FsImage 的文件中,這 個文件也是放在 Namenode 所在的本地文件系統上。
Namenode 在內存中保存著整個文件系統的名字空間和文件數據塊映射 (Blockmap) 的映像 。這個關鍵的元數據結構設計得很緊湊,因而一個有 4G 內存的 Namenode 足夠支撐大量的文件 和目錄。當 Namenode 啟動時,它從硬盤中讀取 Editlog 和 FsImage ,將所有 Editlog 中的事務作 用在內存中的 FsImage 上,并將這個新版本的 FsImage 從內存中保存到本地磁盤上,然后刪除 舊的 Editlog ,因為這個舊的 Editlog 的事務都已經作用在 FsImage 上了。這個過程稱為一個檢查 點 (checkpoint) 。在當前實現中,檢查點只發生在 Namenode 啟動時,在不久的將來將實現支持 周期性的檢查點。
</span>
HDFS NameSpace
HDFS 支持傳統的層次型文件組織結構。用戶或者應用程序可以創建目 錄,然后將文件保存在這些目錄里。文件系統名字空間的層次結構和大多數 現有的文件系統類似:用戶可以創建、刪除、移動或重命名文件。當前, HDFS 不支持用戶磁盤配額和訪問權限控制,也不支持硬鏈接和軟鏈接。但 是 HDFS 架構并不妨礙實現這些特性。Namenode 負責維護文件系統命名空間,任何對文件系統名字空間或屬 性的修改都將被 Namenode 記錄下來。應用程序可以設置 HDFS 保存的文件 的副本數目。文件副本的數目稱為文件的副本系數,這個信息也是由 Namenode 保存的。
</span>
DataNode
Datanode 將 HDFS 數據以文件的形式存儲在本地的文件系統中,它并不知道有 關 HDFS 文件的信息。它把每個 HDFS 數據塊存儲在本地文件系統的一個單獨的文件 中。 Datanode 并不在同一個目錄創建所有的文件,實際上,它用試探的方法來確定 每個目錄的最佳文件數目,并且在適當的時候創建子目錄。在同一個目錄中創建所 有的本地文件并不是最優的選擇,這是因為本地文件系統可能無法高效地在單個目 錄中支持大量的文件。當一個 Datanode 啟動時,它會掃描本地文件系統,產生一個這些本地文件對應 的所有 HDFS 數據塊的列表,然后作為報告發送到 Namenode ,這個報告就是塊狀態 報告。
</span>
配置Secondary NameNode
? conf/masters文件指定的為Secondary NameNode節點?修改在masters文件中配置了的機器上的conf/hdfs-site.xml文件,加上如下選項:
<property>
<name>dfs.http.address</name>
<value>namenode.hadoop-host.com:50070</value>
</property>
?core-site.xml:這里有2個參數可配置,但一般來說我們不做修改。fs.checkpoint.period表示多長時間記錄一次hdfs的鏡像。默認是1小時。fs.checkpoint.size表示一次記錄多大的size,默認64M。
<property>
<name>fs.checkpoint.period</name>
<value>3600</value>
<description>The number of seconds between two periodic checkpoints. </description>
</property>
<property>
<name>fs.checkpoint.size</name>
<value>67108864</value>
<description>The size of the current edit log (in bytes) that triggers a periodic checkpoint even if the fs.checkpoint.period hasn't expired. </description>
</property>
</span>
Secondary NameNode
Secondary NameNode 定期合并 fsimage 和 edits 日志,將 edits 日志文件大小控制在一個限度下。

</span>
Secondary NameNode處理流程
(1) 、 namenode 響應 Secondary namenode 請求,將 edit log 推送給 Secondary namenode , 開始重新寫一個新的 edit log 。(2) 、 Secondary namenode 收到來自 namenode 的 fsimage 文件和 edit log 。
(3) 、 Secondary namenode 將 fsimage 加載到內存,應用 edit log , 并生成一 個新的 fsimage 文件。
(4) 、 Secondary namenode 將新的 fsimage 推送給 Namenode 。
(5) 、 Namenode 用新的 fsimage 取代舊的 fsimage , 在 fstime 文件中記下檢查 點發生的時
HDFS通信協議
所有的 HDFS 通訊協議都是構建在 TCP/IP 協議上。客戶端通過一個可 配置的端口連接到 Namenode , 通過 ClientProtocol 與 Namenode 交互。而 Datanode 是使用 DatanodeProtocol 與 Namenode 交互。再設計上, DataNode 通過周期性的向 NameNode 發送心跳和數據塊來保持和 NameNode 的通信,數據塊報告的信息包括數據塊的屬性,即數據塊屬于哪 個文件,數據塊 ID ,修改時間等, NameNode 的 DataNode 和數據塊的映射 關系就是通過系統啟動時 DataNode 的數據塊報告建立的。從 ClientProtocol 和 Datanodeprotocol 抽象出一個遠程調用 ( RPC ), 在設計上, Namenode 不會主動發起 RPC , 而是是響應來自客戶端和 Datanode 的 RPC 請求。
HDFS的安全模式
Namenode 啟動后會進入一個稱為安全模式的特殊狀態。處于安全模式 的 Namenode 是不會進行數據塊的復制的。 Namenode 從所有的 Datanode 接收心跳信號和塊狀態報告。塊狀態報告包括了某個 Datanode 所有的數據 塊列表。每個數據塊都有一個指定的最小副本數。當 Namenode 檢測確認某 個數據塊的副本數目達到這個最小值,那么該數據塊就會被認為是副本安全 (safely replicated) 的;在一定百分比(這個參數可配置)的數據塊被 Namenode 檢測確認是安全之后(加上一個額外的 30 秒等待時間), Namenode 將退出安全模式狀態。接下來它會確定還有哪些數據塊的副本沒 有達到指定數目,并將這些數據塊復制到其他 Datanode 上。
</span>
2:HDFS文件讀取的解析
文件讀取流程

</span>
流程分析
?使用HDFS提供的客戶端開發庫Client,向遠程的Namenode發起RPC請求;? Namenode會視情況返回文件的部分或者全部block列表,對于每個block,Namenode都會返回有該block拷貝的DataNode地址;
?客戶端開發庫Client會選取離客戶端最接近的DataNode來讀取block;如果客戶端本身就是DataNode,那么將從本地直接獲取數據.
?讀取完當前block的數據后,關閉與當前的DataNode連接,并為讀取下一個block尋找最佳的DataNode;
?當讀完列表的block后,且文件讀取還沒有結束,客戶端開發庫會繼續向Namenode獲取下一批的block列表。
?讀取完一個block都會進行checksum驗證,如果讀取datanode時出現錯誤,客戶端會通知Namenode,然后再從下一個擁有該block拷貝的datanode繼續讀。
</span>
3:HDFS文件寫入的解析
文件寫入流程

</span>
流程分析
?使用HDFS提供的客戶端開發庫Client,向遠程的Namenode發起RPC請求;?Namenode會檢查要創建的文件是否已經存在,創建者是否有權限進行操作,成功則會為文件 創建一個記錄,否則會讓客戶端拋出異常;
?當客戶端開始寫入文件的時候,會將文件切分成多個packets,并在內部以數據隊列"data queue"的形式管理這些packets,并向Namenode申請新的blocks,獲取用來存儲replicas的合適的datanodes列表,列表的大小根據在Namenode中對replication的設置而定。
?開始以pipeline(管道)的形式將packet寫入所有的replicas中。把packet以流的方式寫入第一個datanode,該datanode把該packet存儲之后,再將其傳遞給在此pipeline中的下一個datanode,直到最后一個datanode,這種寫數據的方式呈流水線的形式。
?最后一個datanode成功存儲之后會返回一個ack packet,在pipeline里傳遞至客戶端,在客戶端的開發庫內部維護著"ack queue",成功收到datanode返回的ack packet后會從"ack queue"移除相應的packet。
?如果傳輸過程中,有某個datanode出現了故障,那么當前的pipeline會被關閉,出現故障的datanode會從當前的pipeline中移除,剩余的block會繼續剩下的datanode中繼續以pipeline的形式傳輸,同時Namenode會分配一個新的datanode,保持replicas設定的數量。
</span>
流水線復制
當客戶端向 HDFS 文件寫入數據的時候,一開始是寫到本地臨時文件中。假設該文件的副 本系數設置為 3 ,當本地臨時文件累積到一個數據塊的大小時,客戶端會從 Namenode 獲取一個 Datanode 列表用于存放副本。然后客戶端開始向第一個 Datanode 傳輸數據,第一個 Datanode 一小部分一小部分 (4 KB) 地接收數據,將每一部分寫入本地倉庫,并同時傳輸該部分到列表中 第二個 Datanode 節點。第二個 Datanode 也是這樣,一小部分一小部分地接收數據,寫入本地 倉庫,并同時傳給第三個 Datanode 。最后,第三個 Datanode 接收數據并存儲在本地。因此, Datanode 能流水線式地從前一個節點接收數據,并在同時轉發給下一個節點,數據以流水線的 方式從前一個 Datanode 復制到下一個</span>
更細節的原理
客戶端創建文件的請求其實并沒有立即發送給 Namenode ,事實上,在剛開始階 段 HDFS 客戶端會先將文件數據緩存到本地的一個臨時文件。應用程序的寫操作被透 明地重定向到這個臨時文件。當這個臨時文件累積的數據量超過一個數據塊的大小 ,客戶端才會聯系 Namenode 。 Namenode 將文件名插入文件系統的層次結構中,并 且分配一個數據塊給它。然后返回 Datanode 的標識符和目標數據塊給客戶端。接著 客戶端將這塊數據從本地臨時文件上傳到指定的 Datanode 上。當文件關閉時,在臨 時文件中剩余的沒有上傳的數據也會傳輸到指定的 Datanode 上。然后客戶端告訴 Namenode 文件已經關閉。此時 Namenode 才將文件創建操作提交到日志里進行存儲 。如果 Namenode 在文件關閉前宕機了,則該文件將丟失。</span>
4:副本機制
特點1. 數據類型單一
2. 副本數比較多
3. 寫文件時副本的放置方法
4. 動態的副本創建策略
5. 弱化的副本一致性要求
</span>
副本擺放策略

</span>
修改副本數
1.集群只有三個Datanode,hadoop系統replication=4時,會出現什么情況?對于上傳文件到hdfs上時,當時hadoop的副本系數是幾,這個文件的塊數副本數就會有幾份,無論以后你怎么更改系統副本系統,這個文件的副本數都不會改變,也就說上傳到分布式系統上的文件副本數由當時的系統副本數決定,不會受replication的更改而變化,除非用命令來更改文件的副本數。因為dfs.replication實質上是client參數,在create文件時可以指定具體replication,屬性dfs.replication是不指定具體replication時的采用默認備份數。文件上傳后,備份數已定,修改dfs.replication是不會影響以前的文件的,也不會影響后面指定備份數的文件。只影響后面采用默認備份數的文件。但可以利用hadoop提供的命令后期改某文件的備份數:hadoop fs -setrep -R 1。如果你是在hdfs-site.xml設置了dfs.replication,這并一定就得了,因為你可能沒把conf文件夾加入到你的 project的classpath里,你的程序運行時取的dfs.replication可能是hdfs-default.xml里的 dfs.replication,默認是3。可能這個就是造成你為什么dfs.replication老是3的原因。你可以試試在創建文件時,顯式設定replication。replication一般到3就可以了,大了意義也不大。
</span>
5:HDFS負載均衡
HDFS的數據也許并不是非常均勻的分布在各個DataNode中。一個常見的原因是在現有的集群上經常會增添新的DataNode節點。當新增一個數據塊(一個文件的數據被保存在一系列的塊中)時,NameNode在選擇DataNode接收這個數據塊之前,會考慮到很多因素。其中的一些考慮的是:?將數據塊的一個副本放在正在寫這個數據塊的節點上。
?盡量將數據塊的不同副本分布在不同的機架上,這樣集群可在完全失去某一機架的情況下還能存活。
?一個副本通常被放置在和寫文件的節點同一機架的某個節點上,這樣可以減少跨越機架的網絡I/O。
?盡量均勻地將HDFS數據分布在集群的DataNode中。
</span>
6:HDFS機架感知
HDFS機架感知
通常,大型 Hadoop 集群是以機架的形式來組織的,同一個機架上不同 節點間的網絡狀況比不同機架之間的更為理想。 另外, NameNode 設法將 數據塊副本保存在不同的機架上以提高容錯性。而 HDFS 不能夠自動判斷集群中各個 datanode 的網絡拓撲情況 Hadoop 允 許集群的管理員通過配置 dfs.network.script 參數來確定節點所處的機架。 文 件提供了 IP->rackid 的翻譯。 NameNode 通過這個得到集群中各個 datanode 機器的 rackid 。 如果 topology.script.file.name 沒有設定,則每個 IP 都會翻譯 成 / default-rack 。

</span>
有了機架感知, NameNode 就可以畫出上圖所示的 datanode 網絡拓撲圖。 D1,R1 都是交換機,最底層是 datanode 。 則 H1 的 rackid=/D1/R1/H1 , H1 的 parent 是 R1 , R1 的是 D1 。 這些 rackid 信息可以通過 topology.script.file.name 配置。有了這些 rackid 信息就可以計算出任意兩臺 datanode 之間的距離。
distance(/D1/R1/H1,/D1/R1/H1)=0 相同的 datanode
distance(/D1/R1/H1,/D1/R1/H2)=2 同一 rack 下的不同 datanode
distance(/D1/R1/H1,/D1/R1/H4)=4 同一 IDC 下的不同 datanode
distance(/D1/R1/H1,/D2/R3/H7)=6 不同 IDC 下的 datanode
7:HDFS訪問
訪問方式
HDFS 給應用提供了多種訪問方式。用戶可以通過 Java API 接口訪問,也 可以通過 C 語言的封裝 API 訪問,還可以通過瀏覽器的方式訪問 HDFS 中的文件。8:HDFS 健壯性
HDFS 的主要目標就是即使在出錯的情況下也要保證數據存儲的可靠性。 常見的三種出錯情況是: Namenode 出錯 , Datanode 出錯和網絡割裂 ( network partitions) 。磁盤數據錯誤,心跳檢測和重新復制
每個 Datanode 節點周期性地向 Namenode 發送心跳信號。網絡割裂可能 導致一部分 Datanode 跟 Namenode 失去聯系。 Namenode 通過心跳信號的缺 失來檢測這一情況,并將這些近期不再發送心跳信號 Datanode 標記為宕機 ,不會再將新的 IO 請求發給它們。任何存儲在宕機 Datanode 上的數據將不 再有效。 Datanode 的宕機可能會引起一些數據塊的副本系數低于指定值, Namenode 不斷地檢測這些需要復制的數據塊,一旦發現就啟動復制操作。 在下列情況下,可能需要重新復制:某個 Datanode 節點失效,某個副本遭 到損壞, Datanode 上的硬盤錯誤,或者文件的副本系數增大。數據完整性
從某個 Datanode 獲取的數據塊有可能是損壞的,損壞可能是由 Datanode 的存儲設備錯誤、網絡錯誤或者軟件 bug 造成的。 HDFS 客戶端軟 件實現了對 HDFS 文件內容的校驗和 (checksum) 檢查。當客戶端創建一個新 的 HDFS 文件,會計算這個文件每個數據塊的校驗和,并將校驗和作為一個 單獨的隱藏文件保存在同一個 HDFS 名字空間下。當客戶端獲取文件內容后 ,它會檢驗從 Datanode 獲取的數據跟相應的校驗和文件中的校驗和是否匹 配,如果不匹配,客戶端可以選擇從其他 Datanode 獲取該數據塊的副本。元數據磁盤錯誤
FsImage 和 Editlog 是 HDFS 的核心數據結構。如果這些文件損壞了,整個 HDFS 實例都將失效。因而, Namenode 可以配置成支持維護多個 FsImage 和 Editlog 的副本。任何對 FsImage 或者 Editlog 的修改,都將同步到它們的副 本上。這種多副本的同步操作可能會降低 Namenode 每秒處理的名字空間事 務數量。然而這個代價是可以接受的,因為即使 HDFS 的應用是數據密集的 ,它們也非元數據密集的。當 Namenode 重啟的時候,它會選取最近的完整 的 FsImage 和 Editlog 來使用。Namenode 是 HDFS 集群中的單點故障 (single point of failure) 所在。如果 Namenode 機器故障,是需要手工干預的。目前,自動重啟或在另一臺機器 上做 Namenode 故障轉移的功能還沒實現。
快照
快照支持某一特定時刻的數據的復制備份。利用快照,可以讓 HDFS 在 數據損壞時恢復到過去一個已知正確的時間點。 HDFS 目前還不支持快照功 能,但計劃在將來的版本進行支持。9:HDFS 文件刪除恢復機制
當用戶或應用程序刪除某個文件時,這個文件并沒有立刻從 HDFS 中刪 除。實際上, HDFS 會將這個文件重命名轉移到 /trash 目錄。只要文件還在 /trash 目錄中,該文件就可以被迅速地恢復。文件在 /trash 中保存的時間是可 配置的,當超過這個時間時, Namenode 就會將該文件從名字空間中刪除。 刪除文件會使得該文件相關的數據塊被釋放。注意,從用戶刪除文件到 HDFS 空閑空間的增加之間會有一定時間的延遲。只要被刪除的文件還在 /trash 目錄中,用戶就可以恢復這個文件。如果 用戶想恢復被刪除的文件,他 / 她可以瀏覽 /trash 目錄找回該文件。 /trash 目 錄僅僅保存被刪除文件的最后副本。 /trash 目錄與其他的目錄沒有什么區別 ,除了一點:在該目錄上 HDFS 會應用一個特殊策略來自動刪除文件。目前 的默認策略是刪除 /trash 中保留時間超過 6 小時的文件。將來,這個策略可以 通過一個被良好定義的接口配置。
開啟回收站
hdfs-site.xml
<configuration>
<property>
<name>fs.trash.interval</name>
<value> 1440 </value>
<description>Number ofminutes between trash checkpoints.
If zero, the trashfeature is disabled.
</description>
</property>
</configuration>
1, fs.trash.interval參數設置保留時間為 1440 分鐘(1天)
2, 回收站的位置:在HDFS上的 /user/$USER/.Trash/Current/
10:HDFS 分布式緩存(DistributedCache )
(1)在HDFS上準備好要共享的數據(text、archive、jar),你拼路徑的時候必須加前綴"file://"說明是本地路徑,否則hadoop默認訪問的路徑是hdfs。
(2)DistributedCache 在 Mapper 或者 Reducer 啟動時會被 copy to local,然后被 DistributedCache.getLocalCacheFiles() 調用,運行完 job 后 local cache file 會被刪掉,如果另一個 job 也需要這樣一份文件,需要重新添加、重新緩存,因為在分布式場景下 task 并不知道該 node 是否存在 cache file。如果在同臺機器已經有了dist cache file,不會再次download,DistributedCache 根據緩存文檔修改的時間戳進行追蹤。 在作業執行期間,當前應用程序或者外部程序不能修改緩存文件,所以分布式緩存一般用來緩存只讀文件。
(3)DistributedCache 在添加的時候注意要添加具體的文件,如果你添加目錄,DistributedCache 將不會自動遍歷、識別目錄下的文件。
11:HDFS缺點
大量小文件
因為 Namenode 把文件系統的元數據放置在內存中,所以文件系統所能 容納的文件數目是由 Namenode 的內存大小來決定。一般來說,每一個文件 、文件夾和 Block 需要占據 150 字節左右的空間,所以,如果你有 100 萬個文 件,每一個占據一個 Block ,你就至少需要 300MB 內存。當前來說,數百萬 的文件還是可行的,當擴展到數十億時,對于當前的硬件水平來說就沒法實 現了。還有一個問題就是,因為 Map task 的數量是由 splits 來決定的,所以 用 MR 處理大量的小文件時,就會產生過多的 Maptask ,線程管理開銷將會 增加作業時間。舉個例子,處理 10000M 的文件,若每個 split 為 1M ,那就會 有 10000 個 Maptasks ,會有很大的線程開銷;若每個 split 為 100M ,則只有 100 個 Maptasks ,每個 Maptask 將會有更多的事情做,而線程的管理開銷也 將減小很多。 </p>
</span></span></span></span>