深刻理解HDFS工作機(jī)制
深入理解一個(gè)技術(shù)的工作機(jī)制是靈活運(yùn)用和快速解決問題的根本方法,也是唯一途徑。對(duì)于HDFS來說除了要明白它的應(yīng)用場(chǎng)景和用法以及通用分布式架構(gòu)之外更重要的是理解關(guān)鍵步驟的原理和實(shí)現(xiàn)細(xì)節(jié)。本篇博文首先對(duì)HDFS的重要特性和使用場(chǎng)景做一個(gè)簡(jiǎn)要說明,之后對(duì)HDFS的數(shù)據(jù)讀寫、元數(shù)據(jù)管理以及NameNode、SecondaryNamenode的工作機(jī)制進(jìn)行深入分析。過程中也會(huì)對(duì)一些配置參數(shù)做一個(gè)說明。
一.HDFS的重要特性
First. HDFS是一個(gè)文件系統(tǒng),用于存儲(chǔ)和管理文件,通過統(tǒng)一的命名空間(類似于本地文件系統(tǒng)的目錄樹)。是分布式的,服務(wù)器集群中各個(gè)節(jié)點(diǎn)都有自己的角色和職責(zé)。
Then.
1.HDFS中的文件在物理上是分塊存儲(chǔ)(block),塊的大小可以通過配置參數(shù)( dfs.blocksize)來規(guī)定,默認(rèn)大小在hadoop2.x版本中是128M,之前的版本中是64M。
2.HDFS文件系統(tǒng)會(huì)給客戶端提供一個(gè)統(tǒng)一的抽象目錄樹,客戶端通過路徑來訪問文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
3.目錄結(jié)構(gòu)及文件分塊位置信息(元數(shù)據(jù))的管理由namenode節(jié)點(diǎn)承擔(dān),namenode是HDFS集群主節(jié)點(diǎn),負(fù)責(zé)維護(hù)整個(gè)hdfs文件系統(tǒng)的目錄樹,以及每一個(gè)路徑(文件)所對(duì)應(yīng)的數(shù)據(jù)塊信息(blockid及所在的datanode服務(wù)器)
4.文件的各個(gè)block的存儲(chǔ)管理由datanode節(jié)點(diǎn)承擔(dān),datanode是HDFS集群從節(jié)點(diǎn),每一個(gè)block都可以在多個(gè)datanode上存儲(chǔ)多個(gè)副本(副本數(shù)量也可以通過參數(shù)設(shè)置dfs.replication,默認(rèn)是3)
5.Datanode會(huì)定期向Namenode匯報(bào)自身所保存的文件block信息,而namenode則會(huì)負(fù)責(zé)保持文件的副本數(shù)量,HDFS的內(nèi)部工作機(jī)制對(duì)客戶端保持透明,客戶端請(qǐng)求訪問HDFS都是通過向namenode申請(qǐng)來進(jìn)行。
6.HDFS是設(shè)計(jì)成適應(yīng)一次寫入,多次讀出的場(chǎng)景,且不支持文件的修改。需要頻繁的RPC交互,寫入性能不好。
二.HDFS寫數(shù)據(jù)分析
1.概述
客戶端要向HDFS寫數(shù)據(jù),首先要跟namenode通信以確認(rèn)可以寫文件并獲得接收文件block的datanode,然后客戶端按順序?qū)⑽募饌€(gè)block傳遞給相應(yīng)datanode,并由接收到block的datanode負(fù)責(zé)向其他datanode復(fù)制block的副本。
2.寫數(shù)據(jù)步驟詳解
1)客戶端向namenode發(fā)送上傳文件請(qǐng)求,namenode對(duì)要上傳目錄和文件進(jìn)行檢查,判斷是否可以上傳,并向客戶端返回檢查結(jié)果。
2)客戶端得到上傳文件的允許后讀取客戶端配置,如果沒有指定配置則會(huì)讀取默認(rèn)配置(例如副本數(shù)和塊大小默認(rèn)為3和128M,副本是由客戶端決定的)。向namenode請(qǐng)求上傳一個(gè)數(shù)據(jù)塊。
3)namenode會(huì)根據(jù)客戶端的配置來查詢datanode信息,如果使用默認(rèn)配置,那么最終結(jié)果會(huì)返回同一個(gè)機(jī)架的兩個(gè)datanode和另一個(gè)機(jī)架的datanode。這稱為“機(jī)架感知”策略。
機(jī)架感知:HDFS采用一種稱為機(jī)架感知(rack-aware)的策略來改進(jìn)數(shù)據(jù)的可靠性、可用性和網(wǎng)絡(luò)帶寬的利用率。大型HDFS實(shí)例一般運(yùn)行在跨越多個(gè)機(jī)架的計(jì)算機(jī)組成的集群上,不同機(jī)架上的兩臺(tái)機(jī)器之間的通訊需要經(jīng)過交換機(jī)。
在大多數(shù)情況下,同一個(gè)機(jī)架內(nèi)的兩臺(tái)機(jī)器間的帶寬會(huì)比不同機(jī)架的兩臺(tái)機(jī)器間的帶寬大。通過一個(gè)機(jī)架感知的過程,Namenode可以確定每個(gè)Datanode所屬的機(jī)架id。一個(gè)簡(jiǎn)單但沒有優(yōu)化的策略就是將副本存放在不同的機(jī)架上。
這樣可以有效防止當(dāng)整個(gè)機(jī)架失效時(shí)數(shù)據(jù)的丟失,并且允許讀數(shù)據(jù)的時(shí)候充分利用多個(gè)機(jī)架的帶寬。這種策略設(shè)置可以將副本均勻分布在集群中,有利于當(dāng)組件失效情況下的負(fù)載均衡。但是,因?yàn)檫@種策略的一個(gè)寫操作需要傳輸數(shù)據(jù)塊到多個(gè)機(jī)架,這增加了寫的代價(jià)。在大多數(shù)情況下,副本系數(shù)是3,HDFS的存放策略是將一個(gè)副本存放在本地機(jī)架的節(jié)點(diǎn)上,一個(gè)副本放在同一機(jī)架的另一個(gè)節(jié)點(diǎn)上,***一個(gè)副本放在不同機(jī)架的節(jié)點(diǎn)上。
這種策略減少了機(jī)架間的數(shù)據(jù)傳輸,這就提高了寫操作的效率。機(jī)架的錯(cuò)誤遠(yuǎn)遠(yuǎn)比節(jié)點(diǎn)的錯(cuò)誤少,所以這個(gè)策略不會(huì)影響到數(shù)據(jù)的可靠性和可用性。于此同時(shí),因?yàn)閿?shù)據(jù)塊只放在兩個(gè)(不是三個(gè))不同的機(jī)架上,所以此策略減少了讀取數(shù)據(jù)時(shí)需要的網(wǎng)絡(luò)傳輸總帶寬。
在這種策略下,副本并不是均勻分布在不同的機(jī)架上。三分之一的副本在一個(gè)節(jié)點(diǎn)上,三分之二的副本在一個(gè)機(jī)架上,其他副本均勻分布在剩下的機(jī)架中,這一策略在不損害數(shù)據(jù)可靠性和讀取性能的情況下改進(jìn)了寫的性能。
4)客戶端在開始傳輸數(shù)據(jù)塊之前會(huì)把數(shù)據(jù)緩存在本地,當(dāng)緩存大小超過了一個(gè)數(shù)據(jù)塊的大小,客戶端就會(huì)從namenode獲取要上傳的datanode列表。之后會(huì)在客戶端和***個(gè)datanode建立連接開始流式的傳輸數(shù)據(jù),這個(gè)datanode會(huì)一小部分一小部分(4K)的接收數(shù)據(jù)然后寫入本地倉庫,同時(shí)會(huì)把這些數(shù)據(jù)傳輸?shù)降诙€(gè)datanode,第二個(gè)datanode也同樣一小部分一小部分的接收數(shù)據(jù)并寫入本地倉庫,同時(shí)傳輸給第三個(gè)datanode,依次類推。
這樣逐級(jí)調(diào)用和返回之后,待這個(gè)數(shù)據(jù)塊傳輸完成客戶端后告訴namenode數(shù)據(jù)塊傳輸完成,這時(shí)候namenode才會(huì)更新元數(shù)據(jù)信息記錄操作日志。
5)***個(gè)數(shù)據(jù)塊傳輸完成后會(huì)使用同樣的方式傳輸下面的數(shù)據(jù)塊直到整個(gè)文件上傳完成。
細(xì)節(jié):
a.請(qǐng)求和應(yīng)答是使用RPC的方式,客戶端通過ClientProtocol與namenode通信,namenode和datanode之間使用DatanodeProtocol交互。在設(shè)計(jì)上,namenode不會(huì)主動(dòng)發(fā)起RPC,而是響應(yīng)來自客戶端或 datanode 的RPC請(qǐng)求。客戶端和datanode之間是使用socket進(jìn)行數(shù)據(jù)傳輸,和namenode之間的交互采用nio封裝的RPC。
b.HDFS有自己的序列化協(xié)議。
c.在數(shù)據(jù)塊傳輸成功后但客戶端沒有告訴namenode之前如果namenode宕機(jī)那么這個(gè)數(shù)據(jù)塊就會(huì)丟失。
d.在流式復(fù)制時(shí),逐級(jí)傳輸和響應(yīng)采用響應(yīng)隊(duì)列來等待傳輸結(jié)果。隊(duì)列響應(yīng)完成后返回給客戶端。
c.在流式復(fù)制時(shí)如果有一臺(tái)或兩臺(tái)(不是全部)沒有復(fù)制成功,不影響***結(jié)果,只不過datanode會(huì)定期向namenode匯報(bào)自身信息。如果發(fā)現(xiàn)異常namenode會(huì)指揮datanode刪除殘余數(shù)據(jù)和完善副本。如果副本數(shù)量少于某個(gè)最小值就會(huì)進(jìn)入安全模式。
安全模式:Namenode啟動(dòng)后會(huì)進(jìn)入一個(gè)稱為安全模式的特殊狀態(tài)。處于安全模式的Namenode是不會(huì)進(jìn)行數(shù)據(jù)塊的復(fù)制的。Namenode從所有的 Datanode接收心跳信號(hào)和塊狀態(tài)報(bào)告。塊狀態(tài)報(bào)告包括了某個(gè)Datanode所有的數(shù)據(jù)塊列表。每個(gè)數(shù)據(jù)塊都有一個(gè)指定的最小副本數(shù)。
當(dāng)Namenode檢測(cè)確認(rèn)某個(gè)數(shù)據(jù)塊的副本數(shù)目達(dá)到這個(gè)最小值,那么該數(shù)據(jù)塊就會(huì)被認(rèn)為是副本安全(safely replicated)的;在一定百分比(這個(gè)參數(shù)可配置)的數(shù)據(jù)塊被Namenode檢測(cè)確認(rèn)是安全之后(加上一個(gè)額外的30秒等待時(shí)間),Namenode將退出安全模式狀態(tài)。接下來它會(huì)確定還有哪些數(shù)據(jù)塊的副本沒有達(dá)到指定數(shù)目,并將這些數(shù)據(jù)塊復(fù)制到其他Datanode上。
三.HDFS讀數(shù)據(jù)分析
1.概述
客戶端將要讀取的文件路徑發(fā)送給namenode,namenode獲取文件的元信息(主要是block的存放位置信息)返回給客戶端,客戶端根據(jù)返回的信息找到相應(yīng)datanode逐個(gè)獲取文件的block并在客戶端本地進(jìn)行數(shù)據(jù)追加合并從而獲得整個(gè)文件。
2.讀數(shù)據(jù)步驟詳解
1)客戶端向namenode發(fā)起RPC調(diào)用,請(qǐng)求讀取文件數(shù)據(jù)。
2)namenode檢查文件是否存在,如果存在則獲取文件的元信息(blockid以及對(duì)應(yīng)的datanode列表)。
3)客戶端收到元信息后選取一個(gè)網(wǎng)絡(luò)距離最近的datanode,依次請(qǐng)求讀取每個(gè)數(shù)據(jù)塊。客戶端首先要校檢文件是否損壞,如果損壞,客戶端會(huì)選取另外的datanode請(qǐng)求。
4)datanode與客戶端簡(jiǎn)歷socket連接,傳輸對(duì)應(yīng)的數(shù)據(jù)塊,客戶端收到數(shù)據(jù)緩存到本地,之后寫入文件。
5)依次傳輸剩下的數(shù)據(jù)塊,直到整個(gè)文件合并完成。
從某個(gè)Datanode獲取的數(shù)據(jù)塊有可能是損壞的,損壞可能是由Datanode的存儲(chǔ)設(shè)備錯(cuò)誤、網(wǎng)絡(luò)錯(cuò)誤或者軟件bug造成的。HDFS客戶端軟件實(shí)現(xiàn)了對(duì)HDFS文件內(nèi)容的校驗(yàn)和(checksum)檢查。當(dāng)客戶端創(chuàng)建一個(gè)新的HDFS文件,會(huì)計(jì)算這個(gè)文件每個(gè)數(shù)據(jù)塊的校驗(yàn)和,并將校驗(yàn)和作為一個(gè)單獨(dú)的隱藏文件保存在同一個(gè)HDFS名字空間下。
當(dāng)客戶端獲取文件內(nèi)容后,它會(huì)檢驗(yàn)從Datanode獲取的數(shù)據(jù)跟相應(yīng)的校驗(yàn)和文件中的校驗(yàn)和是否匹配,如果不匹配,客戶端可以選擇從其他Datanode獲取該數(shù)據(jù)塊的副本。
四.HDFS刪除數(shù)據(jù)分析
HDFS刪除數(shù)據(jù)比較流程相對(duì)簡(jiǎn)單,只列出詳細(xì)步驟:
1)客戶端向namenode發(fā)起RPC調(diào)用,請(qǐng)求刪除文件。namenode檢查合法性。
2)namenode查詢文件相關(guān)元信息,向存儲(chǔ)文件數(shù)據(jù)塊的datanode發(fā)出刪除請(qǐng)求。
3)datanode刪除相關(guān)數(shù)據(jù)塊。返回結(jié)果。
4)namenode返回結(jié)果給客戶端。
當(dāng)用戶或應(yīng)用程序刪除某個(gè)文件時(shí),這個(gè)文件并沒有立刻從HDFS中刪除。實(shí)際上,HDFS會(huì)將這個(gè)文件重命名轉(zhuǎn)移到/trash目錄。只要文件還在/trash目錄中,該文件就可以被迅速地恢復(fù)。文件在/trash中保存的時(shí)間是可配置的,當(dāng)超過這個(gè)時(shí)間時(shí),Namenode就會(huì)將該文件從名字空間中刪除。
刪除文件會(huì)使得該文件相關(guān)的數(shù)據(jù)塊被釋放。注意,從用戶刪除文件到HDFS空閑空間的增加之間會(huì)有一定時(shí)間的延遲。只要被刪除的文件還在/trash目錄中,用戶就可以恢復(fù)這個(gè)文件。如果用戶想恢復(fù)被刪除的文件,他/她可以瀏覽/trash目錄找回該文件。/trash目錄僅僅保存被刪除文件的***副本。
/trash目錄與其他的目錄沒有什么區(qū)別,除了一點(diǎn):在該目錄上HDFS會(huì)應(yīng)用一個(gè)特殊策略來自動(dòng)刪除文件。目前的默認(rèn)策略是刪除/trash中保留時(shí)間超過6小時(shí)的文件。將來,這個(gè)策略可以通過一個(gè)被良好定義的接口配置。
當(dāng)一個(gè)文件的副本系數(shù)被減小后,Namenode會(huì)選擇過剩的副本刪除。下次心跳檢測(cè)時(shí)會(huì)將該信息傳遞給Datanode。Datanode遂即移除相應(yīng)的數(shù)據(jù)塊,集群中的空閑空間加大。同樣,在調(diào)用setReplication API結(jié)束和集群中空閑空間增加間會(huì)有一定的延遲。
五.NameNode元數(shù)據(jù)管理原理分析
1.概述
首先明確namenode的職責(zé):響應(yīng)客戶端請(qǐng)求、管理元數(shù)據(jù)。
namenode對(duì)元數(shù)據(jù)有三種存儲(chǔ)方式:
內(nèi)存元數(shù)據(jù)(NameSystem)
磁盤元數(shù)據(jù)鏡像文件
數(shù)據(jù)操作日志文件(可通過日志運(yùn)算出元數(shù)據(jù))
細(xì)節(jié):HDFS不適合存儲(chǔ)小文件的原因,每個(gè)文件都會(huì)產(chǎn)生元信息,當(dāng)小文件多了之后元信息也就多了,對(duì)namenode會(huì)造成壓力。
2.對(duì)三種存儲(chǔ)機(jī)制的進(jìn)一步解釋
內(nèi)存元數(shù)據(jù)就是當(dāng)前namenode正在使用的元數(shù)據(jù),是存儲(chǔ)在內(nèi)存中的。
磁盤元數(shù)據(jù)鏡像文件是內(nèi)存元數(shù)據(jù)的鏡像,保存在namenode工作目錄中,它是一個(gè)準(zhǔn)元數(shù)據(jù),作用是在namenode宕機(jī)時(shí)能夠快速較準(zhǔn)確的恢復(fù)元數(shù)據(jù)。稱為fsimage。
數(shù)據(jù)操作日志文件是用來記錄元數(shù)據(jù)操作的,在每次改動(dòng)元數(shù)據(jù)時(shí)都會(huì)追加日志記錄,如果有完整的日志就可以還原完整的元數(shù)據(jù)。主要作用是用來完善fsimage,減少fsimage和內(nèi)存元數(shù)據(jù)的差距。稱為editslog。
3.checkpoint機(jī)制分析
因?yàn)閚amenode本身的任務(wù)就非常重要,為了不再給namenode壓力,日志合并到fsimage就引入了另一個(gè)角色secondarynamenode。secondarynamenode負(fù)責(zé)定期把editslog合并到fsimage,“定期”是namenode向secondarynamenode發(fā)送RPC請(qǐng)求的,是按時(shí)間或者日志記錄條數(shù)為“間隔”的,這樣即不會(huì)浪費(fèi)合并操作又不會(huì)造成fsimage和內(nèi)存元數(shù)據(jù)有很大的差距。因?yàn)樵獢?shù)據(jù)的改變頻率是不固定的。
每隔一段時(shí)間,會(huì)由secondary namenode將namenode上積累的所有edits和一個(gè)***的fsimage下載到本地,并加載到內(nèi)存進(jìn)行merge(這個(gè)過程稱為checkpoint)。
1)namenode向secondarynamenode發(fā)送RPC請(qǐng)求,請(qǐng)求合并editslog到fsimage。
2)secondarynamenode收到請(qǐng)求后從namenode上讀取(通過http服務(wù))editslog(多個(gè),滾動(dòng)日志文件)和fsimage文件。
3)secondarynamenode會(huì)根據(jù)拿到的editslog合并到fsimage。形成***的fsimage文件。(中間有很多步驟,把文件加載到內(nèi)存,還原成元數(shù)據(jù)結(jié)構(gòu),合并,再生成文件,新生成的文件名為fsimage.checkpoint)。
4)secondarynamenode通過http服務(wù)把fsimage.checkpoint文件上傳到namenode,并且通過RPC調(diào)用把文件改名為fsimage。
namenode和secondary namenode的工作目錄存儲(chǔ)結(jié)構(gòu)完全相同,所以,當(dāng)namenode故障退出需要重新恢復(fù)時(shí),可以從secondary namenode的工作目錄中將fsimage拷貝到namenode的工作目錄,以恢復(fù)namenode的元數(shù)據(jù)。
關(guān)于checkpoint操作的配置:
dfs.namenode.checkpoint.check.period=60 #檢查觸發(fā)條件是否滿足的頻率,60秒
dfs.namenode.checkpoint.dir=file://${hadoop.tmp.dir}/dfs/namesecondary
#以上兩個(gè)參數(shù)做checkpoint操作時(shí),secondary namenode的本地工作目錄
dfs.namenode.checkpoint.edits.dir=${dfs.namenode.checkpoint.dir}
dfs.namenode.checkpoint.max-retries=3 #***重試次數(shù)
dfs.namenode.checkpoint.period=3600 #兩次checkpoint之間的時(shí)間間隔3600秒
dfs.namenode.checkpoint.txns=1000000 #兩次checkpoint之間***的操作記錄
editslog和fsimage文件存儲(chǔ)在$dfs.namenode.name.dir/current目錄下,這個(gè)目錄可以在hdfs-site.xml中配置的。這個(gè)目錄下的文件結(jié)構(gòu)如下:
包括edits日志文件(滾動(dòng)的多個(gè)文件),有一個(gè)是edits_inprogress_*是當(dāng)前正在寫的日志。fsimage文件以及md5校檢文件。seen_txid是記錄當(dāng)前滾動(dòng)序號(hào),代表seen_txid之前的日志都已經(jīng)合并完成。
$dfs.namenode.name.dir/current/seen_txid非常重要,是存放transactionId的文件,format之后是0,它代表的是namenode里面的edits_*文件的尾數(shù),namenode重啟的時(shí)候,會(huì)按照seen_txid的數(shù)字恢復(fù)。所以當(dāng)你的hdfs發(fā)生異常重啟的時(shí)候,一定要比對(duì)seen_txid內(nèi)的數(shù)字是不是你edits***的尾數(shù),不然會(huì)發(fā)生重啟namenode時(shí)metaData的資料有缺少,導(dǎo)致誤刪Datanode上多余Block的信息。
六.總結(jié)
深入理解了以上介紹的工作機(jī)制就可以嘗試運(yùn)用他們解決工作和學(xué)習(xí)中遇到的問題了,只要真正理解了核心原理,所有問題都可以自己找到答案。就是要不斷的學(xué)習(xí)、實(shí)踐、總結(jié),再學(xué)習(xí)、再實(shí)踐、再總結(jié)。這樣才能扎扎實(shí)實(shí)做的出色。共勉。
接下來會(huì)有一篇HDFS常見問題的總結(jié)。