HDFS深度歷險 之 從客戶端邏輯看HDFS寫入機制

說明

除了標(biāo)注之外,本文純屬原創(chuàng),轉(zhuǎn)載請注明出處:http://www.lxweimin.com/p/ea6ef5f5b868

HDFS架構(gòu)簡介

Hadoop的框架最核心的設(shè)計就是:HDFS和MapReduce。HDFS為海量的數(shù)據(jù)提供了存儲,則MapReduce為海量的數(shù)據(jù)提供了計算。本文基于Hadoop 2.7.3源碼,分析本地文件推送(新建/追加)到的HDFS客戶端邏輯。

HDFS架構(gòu)圖
  1. HDFS架構(gòu)主要包含兩種類型的節(jié)點:NameNode和DataNode。
  2. NameNode,其實就是名字節(jié)點,其功能類似于我們常用的磁盤文件系統(tǒng)中的inode。對于HDFS而言,NameNode相當(dāng)于“目錄管理器”和“inode表”。
  3. NameNode保存兩類關(guān)鍵的映射表:
  • 名字空間表:從文件名到數(shù)據(jù)塊(DataBlock)的映射,這部分?jǐn)?shù)據(jù)保存在NameNode服務(wù)器的磁盤。
  • inode表:從數(shù)據(jù)塊(DataBlock)到機器的映射,包括每一個數(shù)據(jù)塊保存在哪一個或者哪幾個機器上。這部分?jǐn)?shù)據(jù)在每次重啟NameNode的時候都會和DataNode通訊并重建。
  1. 對于Hadoop 2.7.3而言,一個DataBlock默認(rèn)是128MB,所以一個文件可能需要N個DataBlock來存儲,那么名字空間表很可能是一個文件名映射到一個DataBlock的數(shù)組。
  2. 關(guān)于這兩張表如何協(xié)作定位文件:
  • 當(dāng)使用文件名訪問文件時,NameNode會查詢名字空間表,根據(jù)這個文件名獲取它所有內(nèi)容對應(yīng)的DataBlock列表(是不是很類似于單機磁盤的數(shù)據(jù)訪問)。此時inode表會查詢每一個DataBlock的信息,包括它所在的位置(DataNode的IP+端口)、DataBlock的ID和時間戳以及里面數(shù)據(jù)的長度(<=128MB)等。
  • 這個DataBlock列表返回到客戶端,客戶端根據(jù)每個DataBlock上的信息(線索),分別連接到每個DataNode上,獲取上面存儲的數(shù)據(jù)。
  1. 客戶端與NameNode、NameNode與DataNode的連接,全部都是通過ProtoBuf的RPC調(diào)用來實現(xiàn)的。關(guān)于ProtoBuf可以參考這里。例如,下面就是追加文件的append請求的RPC協(xié)議:
//摘自hadoop-hdfs-project/hadoop-hdfs/src/main/proto/ClientNamenodeProtocol.proto

//RPC請求
rpc append(AppendRequestProto) returns(AppendResponseProto);

//請求報文
message AppendRequestProto {
  required string src = 1;
  required string clientName = 2;
  optional uint32 flag = 3; // bits set using CreateFlag
}

//應(yīng)答報文
message AppendResponseProto {
  optional LocatedBlockProto block = 1;
  optional HdfsFileStatusProto stat = 2;
}

HDFS寫文件Pipeline機制

HDFS在對文件的寫入方面,只允許數(shù)據(jù)追加到文件末尾,而不允許在文件中間修改文件。因為在文件中間修改文件,需要涉及文件鎖、數(shù)據(jù)塊之類的比較復(fù)雜的邏輯。

Hadoop的文件按照DataBlock分塊,并以DataBlock為單位做冗余(負(fù)載均衡)。HDFS可以指定一個復(fù)制因子(replication),默認(rèn)是保存3份,根據(jù)dfs.replication配置項配置。

下面分析HDFS寫文件的Pipeline流程(藍色線表示用于通訊,紅色線表示數(shù)據(jù)的傳輸路線):

hadoop pipeline流程圖
  • ①客戶端發(fā)送請求到NameNode,請求寫文件/新建數(shù)據(jù)塊。
  • NameNode收到請求后,會給客戶端分配一個數(shù)據(jù)塊,其ID是blk_123456,并指明DataBlock各個拷貝所在的各個DataNode的IP和端口(圖中是分別存在于三個DataNode中)。
  • 這一系列的DataNode稱為Pipeline,也就是數(shù)據(jù)傳輸?shù)墓艿溃簿褪恰綝ataNode_1:50010, DataNode_2:50010, DataNode_3:50010】。
  • ②客戶端收到數(shù)據(jù)塊的信息,開始對DataNode發(fā)起寫的請求,請求報文包括要寫的數(shù)據(jù)塊,要寫的數(shù)據(jù)大小等等。請求成功后,發(fā)送數(shù)據(jù)到第一個DataNode,也就是圖中的DataNode_1,在該請求中包含DataBlock各個拷貝的地址(包含DataNode2和DataNode3的地址):【DataNode_1:50010, DataNode_2:50010, DataNode_3:50010】,發(fā)送完成之后等待DataNode_1返回的ACK報文。
  • ③DataNode_1收到數(shù)據(jù)后,保存數(shù)據(jù),并把數(shù)據(jù)發(fā)送到DataNode_2,Pipeline修改為【DataNode_2:50010, DataNode_3:50010】,發(fā)送完成之后等待DataNode_2返回的ACK報文。
  • ④DataNode_2收到數(shù)據(jù)后,把數(shù)據(jù)發(fā)送到DataNode_3,Pipeline修改為【DataNode_3:50010】,發(fā)送完成之后等待DataNode_2返回的ACK報文。
  • ⑤DataNode_3發(fā)現(xiàn)Pipeline中只有自己,不再有下游的DataNode節(jié)點,于是處理完成之后只需要返回ACK到Pipeline的上游節(jié)點,即DataNode_2。
  • ⑥D(zhuǎn)ataNode_2收到DataNode_3的ACK,于是把ACK發(fā)送到Pipeline的上游節(jié)點,即DataNode_1。
  • ⑦DataNode_1收到DataNode_2的ACK,把ACK發(fā)送到Pipeline的上游節(jié)點,即客戶端。

數(shù)據(jù)發(fā)送至此完成。

HDFS文件推送客戶端

要把本地文件推送到HDFS,可以通過以下兩個命令實現(xiàn):

hadoop fs -appendToFile <localsrc> ... <dst>
hadoop fs -put [-f] [-p] [-l] <localsrc> ... <dst>

跟蹤調(diào)用堆棧發(fā)現(xiàn),這兩個命令最終是調(diào)用DFSOutputStream.java中的代碼實現(xiàn)文件的拷貝。

輔助發(fā)送的相關(guān)類和數(shù)據(jù)結(jié)構(gòu)

這份代碼里面包含了一些用于輔助發(fā)送的類:

  • DFSOutputStream:實現(xiàn)了發(fā)送數(shù)據(jù)的主流程,最主要是繼承自FSOutputSummer這個虛擬類的接口方法writeChunk
  • DataStreamer:繼承自Daemon的后臺線程,主要實現(xiàn)數(shù)據(jù)的流式發(fā)送。
  • ResponseProcessor:同樣繼承自Daemon的后臺線程,主要實現(xiàn)對已發(fā)送數(shù)據(jù)包的ACK報文的接收。

還有一些保存發(fā)送數(shù)據(jù)相關(guān)信息的數(shù)據(jù)結(jié)構(gòu):

  • DFSPacket:表示發(fā)送出去的一個數(shù)據(jù)包,包含相應(yīng)的請求頭部以及相關(guān)標(biāo)志位。
  • LinkedList<DFSPacket> dataQueue:用于保存待發(fā)送的數(shù)據(jù)包。它是主線程DFSOutputStream和發(fā)送線程DataStreamer之間生產(chǎn)者-消費者關(guān)系*的共享數(shù)據(jù)結(jié)構(gòu)。
  • LinkedList<DFSPacket> ackQueue:用于保存已經(jīng)發(fā)送的數(shù)據(jù)包。發(fā)出去的數(shù)據(jù)包還要等待DataNode返回ACK才可以被認(rèn)為是發(fā)送成功。它是發(fā)送線程DataStreamer與ACK接收線程ResponseProcessor之間生產(chǎn)者-消費者關(guān)系的共享數(shù)據(jù)結(jié)構(gòu)。
  • BlockConstructionStage stage:這是一個狀態(tài)變量,整個發(fā)送流程就相當(dāng)于一個狀態(tài)機。

看完上面的數(shù)據(jù)結(jié)構(gòu),整個數(shù)據(jù)發(fā)送流程就很明顯了:
<u>DFSOutputStream把數(shù)據(jù)組裝成DFSPacket對象,放入dataQueue;然后等待發(fā)送線程DataStreamer發(fā)送到DataNode;DataStreamer發(fā)送之后,把DFSPacket對象移動到ackQueue,等待ACK線程ResponseProcessor在收到對應(yīng)的ACK之后把該DFSPacket從隊列移除。</u>

下面主要分析DFSOutputStream.java這個客戶端代碼的執(zhí)行流程。

數(shù)據(jù)發(fā)送的主要流程

  • newStreamForCreate/newStreamForAppend這兩個靜態(tài)函數(shù)用于創(chuàng)建DFSOutputStream對象。一個是用于新建文件,一個用于追加到現(xiàn)有的文件。兩個函數(shù)主要差別在于,前者需要新建一個文件(發(fā)送create的RPC請求到NameNode),后者直接通過發(fā)送append的RPC請求到NameNode,在返回報文中獲取文件最后的一個數(shù)據(jù)塊并開始寫入。
  • newStreamForCreate/newStreamForAppend這兩個函數(shù)返回一個DFSOutputStream的對象,然后被org.apache.hadoop.io.IOUtils.copyBytes()調(diào)用DFSOutputStreamwriteChunk接口函數(shù),把本地的數(shù)據(jù)塊發(fā)送出去。下面主要看writeChunk函數(shù)。這個函數(shù)的參數(shù)主要包括數(shù)據(jù)的緩沖區(qū)、要發(fā)送的數(shù)據(jù)在DataBlock中的offset、還有數(shù)據(jù)的校驗等。
HDFS客戶端數(shù)據(jù)發(fā)送流程.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內(nèi)容

  • 一.HDFS簡介 hdfs是一個文件系統(tǒng),用于存儲文件,通過統(tǒng)一的命名空間——目錄樹來定位文件,并且是分布式的,由...
    卡卡xx閱讀 870評論 0 1
  • 本篇博客講解了HDFS的讀機制和寫機制,通過一個實例演示了HDFS的文件存儲過程,非常通俗易懂。 1、客戶端寫文件...
    Michaelhbjian閱讀 745評論 0 0
  • Hadoop 核心-HDFS 1. HDFS概述 1.1 介紹 在現(xiàn)代的企業(yè)環(huán)境中,單機容量往往無法存儲大量數(shù)據(jù),...
    打開世界的源代碼閱讀 466評論 0 0
  • 從AMQP協(xié)議可以看出,MessageQueue、Exchange和Binding構(gòu)成了AMQP協(xié)議的核心,下面我...
    小波同學(xué)閱讀 528評論 0 1
  • 今天是訓(xùn)練的第四天,也是非常期待的高效閱讀的精髓所在,說真的,這節(jié)課感覺信息量太大,可以回顧的內(nèi)容太多,所以...
    宇宙公民辛欣閱讀 172評論 0 0