關(guān)于HDFS的NameNode和SecondaryNameNode的一些疑問解答
點擊上方 "大數(shù)據(jù)肌肉猿"關(guān)注, 星標(biāo)一起成長
后臺回復(fù)【加群】,進入高質(zhì)量學(xué)習(xí)交流群

Hadoop NameNode詳解
NameNode在內(nèi)存中保存著整個文件系統(tǒng)的名字空間和文件數(shù)據(jù)塊的地址映射(Blockmap)。如果NameNode宕機,那么整個集群就癱瘓了。
整個HDFS可存儲的文件數(shù)受限于NameNode的內(nèi)存大小。
這個關(guān)鍵的元數(shù)據(jù)結(jié)構(gòu)設(shè)計得很緊湊,因而一個有4G內(nèi)存的Namenode就足夠支撐大量的文件和目錄。
NameNode負(fù)責(zé):文件元數(shù)據(jù)信息的操作以及處理客戶端的請求
NameNode管理:HDFS文件系統(tǒng)的命名空間NameSpace。
NameNode維護:文件系統(tǒng)樹(FileSystem)以及文件樹中所有的文件和文件夾的元數(shù)據(jù)信息(matedata),維護文件到塊的對應(yīng)關(guān)系和塊到節(jié)點的對應(yīng)關(guān)系
NameNode文件:namespace鏡像文件(fsimage),操作日志文件(edit log),這些信息被Cache在RAM中,當(dāng)然這兩個文件也會被持久化存儲在本地硬盤。
NameNode記錄:每個文件中各個塊所在的數(shù)據(jù)節(jié)點的位置信息。但它并不永久保存塊的位置信息,因為這些信息在系統(tǒng)啟動時由數(shù)據(jù)節(jié)點重建。從數(shù)據(jù)節(jié)點重建:在nameNode啟動時,DataNode向NameNode進行注冊時發(fā)送給NameNode。
NN和SecondaryNameNode(2NN)工作機制
思考:NameNode中的元數(shù)據(jù)是存儲在哪里的?
首先,我們做個假設(shè),如果存儲在NameNode節(jié)點的磁盤中,因為經(jīng)常需要進行隨機訪問,還有響應(yīng)客戶請求,必然是效率過低。因此,元數(shù)據(jù)需要存放在內(nèi)存中。但如果只存在內(nèi)存中,一旦斷電,元數(shù)據(jù)丟失,整個集群就無法工作了。因此產(chǎn)生在磁盤中備份元數(shù)據(jù)的FsImage。
這樣又會帶來新的問題,當(dāng)在內(nèi)存中的元數(shù)據(jù)更新時,如果同時更新FsImage,就會導(dǎo)致效率過低,但如果不更新,就會發(fā)生一致性問題,一旦NameNode節(jié)點斷電,就會產(chǎn)生數(shù)據(jù)丟失。
因此,引入Edits文件(只進行追加操作,效率很高)。每當(dāng)元數(shù)據(jù)有更新或者添加元數(shù)據(jù)時,修改內(nèi)存中的元數(shù)據(jù)并追加到Edits中。這樣,一旦NameNode節(jié)點斷電,可以通過FsImage和Edits的合并,合成元數(shù)據(jù)。
但是,如果長時間添加數(shù)據(jù)到Edits中,會導(dǎo)致該文件數(shù)據(jù)過大,效率降低,而且一旦斷電,恢復(fù)元數(shù)據(jù)需要的時間過長。因此,需要定期進行FsImage和Edits的合并,如果這個操作由NameNode節(jié)點完成,又會效率過低。因此,引入一個新的節(jié)點SecondaryNamenode,專門用于FsImage和Edits的合并。
Fsimage:NameNode內(nèi)存中元數(shù)據(jù)序列化后形成的文件。
Edits:記錄客戶端更新元數(shù)據(jù)信息的每一步操作(可通過Edits運算出元數(shù)據(jù))。
NameNode啟動時,先滾動Edits并生成一個空的edits.inprogress,然后加載Edits和Fsimage到內(nèi)存中,此時NameNode內(nèi)存就持有最新的元數(shù)據(jù)信息。Client開始對NameNode發(fā)送元數(shù)據(jù)的增刪改的請求,這些請求的操作首先會被記錄到edits.inprogress中(查詢元數(shù)據(jù)的操作不會被記錄在Edits中,因為查詢操作不會更改元數(shù)據(jù)信息),如果此時NameNode掛掉,重啟后會從Edits中讀取元數(shù)據(jù)的信息。然后,NameNode會在內(nèi)存中執(zhí)行元數(shù)據(jù)的增刪改的操作。
由于Edits中記錄的操作會越來越多,Edits文件會越來越大,導(dǎo)致NameNode在啟動加載Edits時會很慢,所以需要對Edits和Fsimage進行合并(所謂合并,就是將Edits和Fsimage加載到內(nèi)存中,照著Edits中的操作一步步執(zhí)行,最終形成新的Fsimage)。SecondaryNameNode的作用就是幫助NameNode進行Edits和Fsimage的合并工作。
SecondaryNameNode首先會詢問NameNode是否需要CheckPoint(觸發(fā)CheckPoint需要滿足兩個條件中的任意一個,定時時間到和Edits中數(shù)據(jù)寫滿了)。直接帶回NameNode是否檢查結(jié)果。SecondaryNameNode執(zhí)行CheckPoint操作,首先會讓NameNode滾動Edits并生成一個空的edits.inprogress,滾動Edits的目的是給Edits打個標(biāo)記,以后所有新的操作都寫入edits.inprogress,其他未合并的Edits和Fsimage會拷貝到SecondaryNameNode的本地,然后將拷貝的Edits和Fsimage加載到內(nèi)存中進行合并,生成fsimage.chkpoint,然后將fsimage.chkpoint拷貝給NameNode,重命名為Fsimage后替換掉原來的Fsimage。NameNode在啟動時就只需要加載之前未合并的Edits和Fsimage即可,因為合并過的Edits中的元數(shù)據(jù)信息已經(jīng)被記錄在Fsimage中。
HDFS 進程各自的職責(zé)以及如何協(xié)調(diào)工作

Active NameNode:它是 HDFS 對外提供讀寫服務(wù)的唯一 Master 節(jié)點,管理著文件系統(tǒng)的 Namespace;維護著文件的元數(shù)據(jù),包括文件名、副本數(shù)、文件的 BlockId 以及 Block 所在的服務(wù)器等信息;同時會接受來自 Client 端的讀寫請求,和接受 DataNode 的 Block 信息上報。
Standby NameNode:Active NameNode 的備用節(jié)點,它會及時從 JournalNode 中讀取 EditLog 數(shù)據(jù)并更新內(nèi)存,以保證當(dāng)前狀態(tài)盡可能與主節(jié)點同步。需要注意的是,集群中最多一臺處于 Active 狀態(tài),最多一臺處于 Standby 狀態(tài)。
JournalNode Cluster:用于主備 NameNode 之間共享 Editlog 的一致性共享存儲系統(tǒng)。負(fù)責(zé)存儲 Editlog 以及將元數(shù)據(jù)從主節(jié)點實時同步到備用節(jié)點。流程是主節(jié)點先將 EditLog 文件 push 進 JournalNode,備節(jié)點再從 JournalNode 節(jié)點 Pull 數(shù)據(jù),JournalNode 不主動進行數(shù)據(jù)交換。集群由 2N + 1 個 JournalNode 進程組成,可以容忍最多 N 臺 JournalNode 節(jié)點掛掉。
ZKFailoverController(ZKFC):ZKFailoverController 以獨立進程運行,正常情況每個 ZKFC 都會監(jiān)控自己負(fù)責(zé)的 NameNode 的心跳,如果異常,則會斷開與 ZooKeeper 的連接,釋放分布式鎖,另外一個 NameNode 上的 ZKFC 則會獲取鎖,然后會把對應(yīng)的 NameNode 的狀態(tài)從 Standby 切換到 Active。ZKFC 主要負(fù)責(zé):NameNode 健康狀況檢測;借助 Zookeeper 實現(xiàn) NameNode 自動選主;操作 NameNode 進行主從切換。
Zookeeper:為 ZKFC 實現(xiàn)自動選主功能提供統(tǒng)一協(xié)調(diào)服務(wù)。通過 watcher 監(jiān)聽機制,通知 ZKFC 異常 NameNode 的下線;保證同一時刻只有一個 Active Name 節(jié)點,并告知客戶端。
DataNode:負(fù)責(zé)實際數(shù)據(jù)的存儲,在如圖 NameNode 高可用的架構(gòu)下,DataNode 會同時向主備兩個 NameNode 節(jié)點進行元數(shù)據(jù)上報,但是僅執(zhí)行主節(jié)點下發(fā)的指令。
相關(guān)面試題
HDFS 客戶端與 NameNode 和 DataNode 的通信和交互過程?
Secondary NameNode 的功能在高可用架構(gòu)下被那個進程所取代?
NameNode 會存儲哪些數(shù)據(jù)?
HDFS 是如何保證 NameNode 高可用的?
ZKFC 是如何實現(xiàn)主節(jié)點異常切換的?
Zookeeper 在異常切換中起到的作用?
Block & Packet & Chunk
Block:HDFS 中的文件在物理上是分塊存儲,即 Block。每個 Block 大?。篐adoop 2.x 版本為 128 MB;Hadoop 1.x 版本為 64 MB 。
Packet:Packet 是 Client 端向 DataNode,或 DataNode 的 PipLine 之間傳數(shù)據(jù)的基本單位,默認(rèn) 64KB。
Chunk:Chunk 是最小的單位,它是 Client 向 DataNode 或 DataNode 的 PipLine 之間進行數(shù)據(jù)校驗的基本單位,默認(rèn) 512Byte,因為用作校驗,故每個 chunk 需要帶有 4 Byte 的校驗位。所以實際每個 chunk 寫入 packet 的大小為 516 Byte。
安全模式
HDFS 可用 Block 占總數(shù)的比例(dfs.namenode.safemode.threshold-pct):默認(rèn) 99.9%
可用的數(shù)據(jù)節(jié)點數(shù)量符合要求(dfs.namenode.safemode.min.datanodes):默認(rèn) 0,即無要求。
滿足上面兩個條件的持續(xù)時間(dfs.namenode.safemode.extension):默認(rèn) 1ms,即維持正常狀態(tài) 1ms 就退出安全模式。
源碼級客戶端讀寫數(shù)據(jù)交互流程
寫數(shù)據(jù)流程?

首先 client 端通過在 DistributedFileSystem 上調(diào)用 create() 方法來創(chuàng)建一個文件。其中,DistributedFileSystem 是客戶端用戶創(chuàng)建的一個對象,用戶可以通過調(diào)用 DistributedFileSystem 的方法來對 HDFS 做讀寫操作。
在收到 client 端 create 動作之后,DistributedFileSystem 通過 RPC 與 NameNode 通信 ,讓它在文件系統(tǒng)的 namespace 上創(chuàng)建一個獨立的新文件,NameNode 會確認(rèn)文件是否已經(jīng)存在以及客戶端是否有權(quán)限。確認(rèn)成功后,NameNode 會生成一條新文件的記錄并返回一個負(fù)責(zé) client 端與 datanode 和 namenode 進行 I/O 操作的 DFSOutputStream 對象給客戶端,另外還會包含可寫入的 DataNode 的信息。如文件創(chuàng)建失敗,客戶端會拋出一個 IOException。
當(dāng)客戶端開始寫數(shù)據(jù),DFSOutputStream 將文件分割成很多很小的塊,然后將每個小塊放進一個個 package 中, packages 會寫進一個內(nèi)部隊列中,準(zhǔn)備往 DataNode 寫數(shù)據(jù)。
此時會根據(jù) NameNode 返回的可寫入的 DataNode 列表來構(gòu)成一個 pipeline,默認(rèn)是有三個 DataNode 組成, DataStreamer 將能夠組成塊的包先流入 pipeline 中的第一個 DataNode ,第一個 DataNode 會先存儲來到的包,然后繼續(xù)將所有的包轉(zhuǎn)交到 pipeline 中的第二個 DataNode 中,以此類推。
DFSOutputStream 還維護了另一個確認(rèn)隊列,該隊列等待 DataNode 的寫入確認(rèn)。當(dāng)一個包已經(jīng)被 pipeline 中的所有 DataNode 確認(rèn)了寫如磁盤成功,這個包才會從確認(rèn)隊列中移除。
當(dāng) Client 完成了數(shù)據(jù)寫入,會在流上調(diào)用 close() 方法。需注意,這一步不是在 4 和 5 第一次完成之后,而是客戶端需要寫入的所有數(shù)據(jù)寫完了之后。這個行為會將所有剩下的包 flush 進 DataNode 中。
等到確認(rèn)信息全部都到達,即步驟 5 完成之后,Client 會再次與 NameNode 通信告知完成。NameNode 會確認(rèn)該文件的備份數(shù)是否滿足要求。
讀數(shù)據(jù)流程?

與寫流程類似,第一步 Client 端同樣是調(diào)用 DistributedFileSystem 對象,指定想要讀的文件 target.txt ,使用 open() 方法。
此時 DistributedFileSystem 就會與 NameNode 進行 RPC 通信,獲取組成 target.txt 的 block 信息,其中包含** block 存在于哪些 DataNode 中**。
然后 Client 就調(diào)用 read() 方法,這里同樣會有一個 DFSInputStream 來負(fù)責(zé)與 DataNode 的 IO。此時會找到 DataNode 列表里離當(dāng)前 Client 端最近的一個 DataNode(如何判斷最近,后面的機架感知中會解釋)。
然后 DFSInputStream 就通過重復(fù)調(diào)用 read() 方法,數(shù)據(jù)就從 DataNode 流動到了客戶端。當(dāng)該 DataNode 中最后一個塊的讀取完成了, DFSInputStream 會關(guān)閉與 DataNode 的連接,然后為下一塊尋找最佳節(jié)點。這個過程對客戶端來說是透明的,在客戶端那邊看來,就像是只讀取了一個連續(xù)不斷的流。
當(dāng)客戶端完成了讀取,就會調(diào)用 close() 方法結(jié)束整個流程。**
HDFS 可用性保證機制
首先 NameNode 的高可用由 JournalNode 和 DFSZKFailoverController 保證,NameNode 有主備兩個節(jié)點,JournalNode 負(fù)責(zé)主備節(jié)點數(shù)據(jù)的同步保證數(shù)據(jù)一致性,ZKFC 負(fù)責(zé)主備的 Failover,即主節(jié)點宕機由備用節(jié)點接替主節(jié)點工作。
JournalNode 也是分布式的,因為有選舉機制,所以默認(rèn)要大于一的奇數(shù)個服務(wù)器在線,同樣是具有可用性保證的。
DFSZKFailoverController(ZKFC)是部署在兩個 NameNode 節(jié)點上的獨立的進程,他的作用是輔助 zookeeper 做 NameNode 的健康監(jiān)控,保證異常切換,而 **Zookeeper **是一個獨立的分布式系統(tǒng),用于管理和協(xié)調(diào)分布式系統(tǒng)的工作,它本身也會通過 zab 協(xié)議來保證數(shù)據(jù)一致,和主備節(jié)點的選舉切換等機制來保證可用性。
DataNode節(jié)點的宕機會造成部分 block 的丟失,但是 block 一般都會有三個備份,且在不同的 DataNode,所以 DataNode 掛掉兩臺仍然能保證數(shù)據(jù)的完整性,同時NameNode 會負(fù)責(zé)副本數(shù)的補充。
對于數(shù)據(jù)的可用性保證,HDFS 還提供了數(shù)據(jù)完整性校驗的機制,當(dāng)客戶端創(chuàng)建 HDFS 文件時,它會計算文件的每個塊的校驗和(checknums),并存儲在 NameNode 中。當(dāng)客戶端讀文件時,會驗證從每個 DataNode 接收的數(shù)據(jù)是否與 checknums 匹配。如果匹配失敗,則證明數(shù)據(jù)已經(jīng)損壞,此時客戶端會選擇從其他 DataNode 獲取該塊的其他可用副本。
--end--
掃描下方二維碼
添加好友,備注【交流】
可私聊交流,也可進資源豐富學(xué)習(xí)群
更文不易,點個“在看”支持一下??
