剖析文件的讀取
為了了解客戶(hù)端及與之交互的HDFS、namenode 和 datanode之間的數(shù)據(jù)流是什么樣的,我們可以參考下圖,該圖顯示了在讀取文件時(shí)事件的發(fā)生順序。
客戶(hù)端通過(guò)調(diào)用FileSystem對(duì)象的open()方法來(lái)打開(kāi)希望讀取的文件,對(duì)于HDFS來(lái)說(shuō),這個(gè)對(duì)象是分布式文件系統(tǒng)(圖中步驟1)的一個(gè)實(shí)例。DistributedFileSystem 通過(guò)使用RPC來(lái)調(diào)用namenode,以確定文件起始?jí)K的位置(步驟2)。對(duì)于每一個(gè)塊,namenode返回存有該塊副本的datanode地址。此外,這些datanode根據(jù)它們與客戶(hù)端的距離來(lái)排序。如果該客戶(hù)端本身就是一個(gè)datanode(比如,在一個(gè)MapReduce任務(wù)中),并保存有相應(yīng)數(shù)據(jù)塊的一個(gè)副本時(shí),該節(jié)點(diǎn)就會(huì)從本地datanode讀取數(shù)據(jù)。
DistributedFileSystem類(lèi)返回一個(gè)FSDataInputStream對(duì)象(一個(gè)支持文件定位的數(shù)據(jù)流)給客戶(hù)端并讀取數(shù)據(jù)。FSDataInputStream類(lèi)轉(zhuǎn)而封裝DFSInputStream對(duì)象,該對(duì)象管理著datanode和namenode的I/O。
接著,客戶(hù)端對(duì)這個(gè)輸入流調(diào)用 read()方法(步驟3)。存儲(chǔ)著文件起始幾個(gè)塊的datanode地址的DFSInputStream隨即連接距離最近的datanode。通過(guò)對(duì)數(shù)據(jù)反復(fù)調(diào)用read()方法,可以將數(shù)據(jù)從datanode傳輸?shù)娇蛻?hù)端(步驟4)。到達(dá)塊的末端時(shí),DFSInputStream關(guān)閉與該datanode的連接,然后尋找下一個(gè)塊的最佳datanode(步驟5)??蛻?hù)端只需要讀取連續(xù)的流,并且對(duì)客戶(hù)端都是透明的。
客戶(hù)端從流中讀取數(shù)據(jù)時(shí),塊是按照打開(kāi)DFSInputStream與datanode新建連接的順序讀取的。它也會(huì)根據(jù)需要詢(xún)問(wèn)namenode來(lái)檢索下一批數(shù)據(jù)塊的datanode的位置。一旦客戶(hù)端完成讀取,就對(duì)FSDataInputStream調(diào)用close()方法(步驟6)。
在讀取數(shù)據(jù)的時(shí)候,如果DFSInputStream在與datanode通信時(shí)遇到錯(cuò)誤,會(huì)嘗試從這個(gè)塊的另一個(gè)最鄰近datanode讀取數(shù)據(jù)。它也會(huì)記住那個(gè)故障datanode,以保證以后不會(huì)反復(fù)讀取該節(jié)點(diǎn)上后續(xù)的塊。DFSInputStream也會(huì)通過(guò)校驗(yàn)和確認(rèn)從datanode發(fā)來(lái)的數(shù)據(jù)是否完整。 如果發(fā)現(xiàn)有損壞的塊,就在DFSInputStream試圖從其他datanode讀取其副本之前通知namenode。
這個(gè)設(shè)計(jì)的一個(gè)重點(diǎn)是,namenode告知客戶(hù)端每個(gè)塊中最佳的datanode,并讓客戶(hù)端直接連接到該datanode檢索數(shù)據(jù)。由于數(shù)據(jù)流分散在急群眾的所有datanode,所以這種設(shè)計(jì)能使HDFS可擴(kuò)展到大量的并發(fā)客戶(hù)端。同時(shí),namenode只需要響應(yīng)塊位置的請(qǐng)求(這些信息存儲(chǔ)在內(nèi)存中,因而非常高效),無(wú)需響應(yīng)數(shù)據(jù)請(qǐng)求,否則隨著客戶(hù)端數(shù)量的增長(zhǎng),namenode會(huì)很快成為瓶頸。
網(wǎng)絡(luò)拓?fù)渑cHadoop
在本地網(wǎng)絡(luò)里,兩個(gè)節(jié)點(diǎn)被稱(chēng)為“彼此近鄰”是什么意思?在海量數(shù)據(jù)處理中,其主要限制因素是節(jié)點(diǎn)之間數(shù)據(jù)的傳輸速率——帶寬很稀缺。這里的想法是將兩個(gè)節(jié)點(diǎn)間的帶寬作為距離的衡量標(biāo)準(zhǔn)。 不用衡量節(jié)點(diǎn)之間的帶寬——實(shí)際上很難實(shí)現(xiàn)(它需要一個(gè)穩(wěn)定的集群,并且在集群中兩兩節(jié)點(diǎn)對(duì)數(shù)量是節(jié)點(diǎn)數(shù)量的平方)——Hadoop為此采用一個(gè)簡(jiǎn)單的方法:把網(wǎng)絡(luò)看做一棵樹(shù),兩個(gè)節(jié)點(diǎn)間的距離是它們到最近共同祖先的距離總和。該樹(shù)中的層次是沒(méi)有預(yù)先設(shè)定的,但是相對(duì)于數(shù)據(jù)中心、幾家和正在運(yùn)行的節(jié)點(diǎn),通??梢栽O(shè)定等級(jí)。具體想法是針對(duì)以下每個(gè)場(chǎng)景,可用帶寬依次遞減:
例如,假設(shè)有數(shù)據(jù)中心 d1 機(jī)架 r1 中的節(jié)點(diǎn) n1.該節(jié)點(diǎn)可以表示為/d1/r1/n1。利用這種標(biāo)記,這里給出四種距離描述:
最后,我們必須意識(shí)到Hadoop無(wú)法自行定義網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)。它需要我們能夠理解并輔助定義。 |
剖析文件的寫(xiě)入
接下來(lái)我們看看文件時(shí)如何寫(xiě)入HDFS的,盡管比較詳細(xì),但對(duì)于理解數(shù)據(jù)流還是很有用的,因?yàn)樗宄卣f(shuō)明了HDFS的一致模型。
我們要考慮的情況是如何新建一個(gè)文件,把數(shù)據(jù)寫(xiě)入該文件,最后關(guān)閉該文件。見(jiàn)下圖。
客戶(hù)端通過(guò)對(duì)DistributedFileSystem對(duì)象調(diào)用create()函數(shù)來(lái)新建文件(步驟1)。DistributedFileSystem對(duì)namenode創(chuàng)建一個(gè)RPC調(diào)用,在文件系統(tǒng)的命名空間中新建一個(gè)文件,此時(shí)該文件中還沒(méi)有相應(yīng)的數(shù)據(jù)塊(步驟2)。namenode執(zhí)行各種不同的檢查以確保這個(gè)文件不存在以及客戶(hù)端有新建文件的權(quán)限。如果這些檢查均通過(guò),namenode就會(huì)為創(chuàng)建新文件記錄一條記錄;否則,文件創(chuàng)建失敗并向客戶(hù)端拋出一個(gè)IOException異常。DistributedFileSystem向客戶(hù)端返回一個(gè)FSDataOutputStream對(duì)象,由此客戶(hù)端可以開(kāi)始寫(xiě)入數(shù)據(jù)。就像讀取事件一樣,F(xiàn)SDataOutputStream封裝一個(gè)DFSoutPutstream對(duì)象,該對(duì)象負(fù)責(zé)處理datanode和namenode之間的通信。
在客戶(hù)端寫(xiě)入數(shù)據(jù)時(shí)(步驟3),DFSOutputStream將它分成一個(gè)個(gè)的數(shù)據(jù)包,并寫(xiě)入內(nèi)部隊(duì)列,稱(chēng)為“數(shù)據(jù)隊(duì)列”(data queue)。DataStreamer處理數(shù)據(jù)隊(duì)列,它的責(zé)任是根據(jù)datanode列表來(lái)要求namenode分配適合的新塊來(lái)存儲(chǔ)數(shù)據(jù)復(fù)本。這一組datanode構(gòu)成一個(gè)管線——我們假設(shè)復(fù)本數(shù)為3,所以管線中有3個(gè)節(jié)點(diǎn)。DataStreamer將數(shù)據(jù)包流式傳輸?shù)焦芫€中第一個(gè)datanode,該datanode存儲(chǔ)數(shù)據(jù)包并將它發(fā)送到管線中的第二個(gè)datanode。同樣,第二個(gè)datanode存儲(chǔ)該數(shù)據(jù)包并且發(fā)送給管線中的第三個(gè)(也是最后一個(gè))datanote(步驟4)。
DFSOutputStream也維護(hù)著一個(gè)內(nèi)部數(shù)據(jù)包隊(duì)列來(lái)等待datanode的收到確認(rèn)回執(zhí),稱(chēng)為“確認(rèn)隊(duì)列”(ack queue)。收到管道中所有datanode確認(rèn)信息后,該數(shù)據(jù)包才會(huì)從確認(rèn)隊(duì)列刪除(步驟5)。
如果數(shù)據(jù)在寫(xiě)入期間datanode發(fā)生故障,則執(zhí)行以下操作(對(duì)寫(xiě)入數(shù)據(jù)的客戶(hù)端是透明的)。首先關(guān)閉管線,確認(rèn)把隊(duì)列中的所有數(shù)據(jù)包都添加回?cái)?shù)據(jù)隊(duì)列的最前端,以確保故障節(jié)點(diǎn)下游的datanode不會(huì)漏掉任何一個(gè)數(shù)據(jù)包。為存儲(chǔ)在另一正常datanode的當(dāng)前數(shù)據(jù)結(jié)塊指定一個(gè)新的標(biāo)識(shí),并將該標(biāo)識(shí)傳送給namenode,以便故障datanode在恢復(fù)后可以刪除存儲(chǔ)的部分?jǐn)?shù)據(jù)塊。從管線中刪除故障數(shù)據(jù)節(jié)點(diǎn)并且把余下的數(shù)據(jù)塊寫(xiě)入管線中另外兩個(gè)正常的datanode。namenode注意到塊復(fù)本量不足時(shí),會(huì)在另一個(gè)節(jié)點(diǎn)上創(chuàng)建一個(gè)新的復(fù)本。后續(xù)的數(shù)據(jù)塊繼續(xù)正常接受處理。
在一個(gè)塊被寫(xiě)入期間可能會(huì)有多個(gè)datanode同時(shí)發(fā)生故障,但非常少見(jiàn)。只要寫(xiě)入了dfs.replication.min的復(fù)本數(shù)(默認(rèn)為1),寫(xiě)操作就會(huì)成功,并且這個(gè)塊可以在集群中異步復(fù)制,直到達(dá)到其目標(biāo)復(fù)本數(shù)(dfs.replication的默認(rèn)值為3)。
客戶(hù)端完成數(shù)據(jù)的寫(xiě)入后,對(duì)數(shù)據(jù)流調(diào)用close()方法(步驟6)。該操作將剩余的所有數(shù)據(jù)包寫(xiě)入datanode管線,并在聯(lián)系到namenode且發(fā)送文件寫(xiě)入完成信號(hào)之前,等待確認(rèn)(步驟7)。namenode已經(jīng)知道文件由哪些塊組成(通過(guò)Datastreamer請(qǐng)求分配數(shù)據(jù)塊),所以它在返回成功之前只需要等待數(shù)據(jù)塊進(jìn)行最小量的復(fù)制。
復(fù)本怎么放
namenode如何選擇在哪個(gè)datanode存儲(chǔ)復(fù)本(replica)?這里需要對(duì)可靠性、寫(xiě)入帶寬和讀取帶寬進(jìn)行權(quán)衡。例如,把所有復(fù)本都存儲(chǔ)在一個(gè)節(jié)點(diǎn)損失的寫(xiě)入帶寬最小,因?yàn)閺?fù)制管線都是在同一個(gè)節(jié)點(diǎn)上運(yùn)行,但這并不提供真實(shí)的冗余(如果節(jié)點(diǎn)發(fā)生故障,那么該塊中的數(shù)據(jù)會(huì)丟失)。同時(shí),同一機(jī)架上服務(wù)器間的讀取帶寬是很高的。另一個(gè)極端,把復(fù)本放在不同的數(shù)據(jù)中心可以大限度地提高冗余,但帶寬的損耗非常大。即使在同一數(shù)據(jù)中心(到目前為止,所有Hadoop集群均運(yùn)行在同一數(shù)據(jù)中心內(nèi)),也有許多不同的數(shù)據(jù)布局策略。其實(shí),在發(fā)布的Hadoop 0.17.0版中改變了數(shù)據(jù)布局策略來(lái)復(fù)制保持?jǐn)?shù)據(jù)塊在集群內(nèi)分布相對(duì)均勻。在1.x之后的發(fā)行版本,可即時(shí)選擇數(shù)據(jù)塊的布局策略。 Hadoop的默認(rèn)布局策略是在運(yùn)行客戶(hù)端的節(jié)點(diǎn)上放第一個(gè)復(fù)本(如果客戶(hù)端運(yùn)行在集群之外,就隨機(jī)選擇一個(gè)節(jié)點(diǎn),不過(guò)系統(tǒng)會(huì)避免挑選那些存儲(chǔ)太慢或太忙的節(jié)點(diǎn))。第二個(gè)復(fù)本放在與第一個(gè)不同且隨機(jī)另外選擇的機(jī)架中節(jié)點(diǎn)上(離架)。第三個(gè)復(fù)本與第二個(gè)復(fù)本放在同一個(gè)機(jī)架上,且隨機(jī)選擇另一個(gè)節(jié)點(diǎn)。其他復(fù)本放在集群中隨機(jī)選擇的節(jié)點(diǎn)上,不過(guò)系統(tǒng)會(huì)盡量避免在同一個(gè)機(jī)架上放太多復(fù)本。 一旦選定復(fù)本的放置位置,就根據(jù)網(wǎng)絡(luò)拓?fù)鋭?chuàng)建一個(gè)管線(Pipeline)。如果復(fù)本數(shù)為3,則有下圖所示的管線。 總的來(lái)說(shuō),這一方法不僅提供很好的穩(wěn)定性(數(shù)據(jù)塊存儲(chǔ)在兩個(gè)機(jī)架中)并實(shí)現(xiàn)很好的負(fù)載均衡,包括寫(xiě)入帶寬(寫(xiě)入操作只需要遍歷一個(gè)交換機(jī))、讀取性能(可以從兩個(gè)機(jī)架中選擇讀?。┖图褐袎K的均勻分布(客戶(hù)端只在本地機(jī)架上寫(xiě)入一個(gè)塊)。 |
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。