Hadoop(六)之HDFS的存儲原理(運行原理)


閱讀目錄(Content)

  • 一、HDFS讀取過程
  • 二、HDFS的寫入過程
  • 三、通過實例說明HDFS的讀寫操作
    • 3.1、寫入操作
    • 3.2、讀取操作
  • 四、圖解HDFS的讀取寫入過程
    • 4.1、角色出演
    • 4.2、讀取操作
    • 3.2、寫入操作

前言

  其實說到HDFS的存儲原理,無非就是讀操作和寫操作,那接下來我們詳細的看一下HDFS是怎么實現讀寫操作的!

一、HDFS讀取過程

  

  1)客戶端通過調用FileSystem對象的open()來讀取希望打開的文件。對於HDFS來說,這個對象是分布式文件系統的一個實例。

  2)DistributedFileSystem通過RPC來調用namenode,以確定文件的開頭部分的塊位置。對於每一塊,namenode返回具有該塊副本的datanode地址。

    此外,這些datanode根據他們與client的距離來排序(根據網絡集群的拓撲)。如果該client本身就是一個datanode,便從本地datanode中讀取。

           DistributedFileSystem返回一個FSDataInputStream對象給client讀取數據,FSDataInputStream轉而包裝了一個DFSInputStream對象。

  3)接着client對這個輸入流調用read()。存儲着文件開頭部分的塊的數據節點的地址DFSInputStream隨即與這些塊最近的datanode相連接。

  4)通過在數據流中反復調用read(),數據會從datanode返回client。

  5)到達塊的末端時,DFSInputStream會關閉與datanode間的聯系,然后為下一個塊找到最佳的datanode。client端只需要讀取一個連續的流,這些對於client來說都是透明的。

  6)在讀取的時候,如果client與datanode通信時遇到一個錯誤,那么它就會去嘗試對這個塊來說下一個最近的塊。它也會記住那個故障節點的datanode,以保證不會再對之后的塊進行徒勞無益的嘗試。

    client也會確認datanode發來的數據的校驗和。如果發現一個損壞的塊,它就會在client試圖從別的datanode中讀取一個塊的副本之前報告給namenode。

  7)這個設計的一個重點是,client直接聯系datanode去檢索數據,並被namenode指引到塊中最好的datanode。因為數據流在此集群中是在所有datanode分散進行的。

    所以這種設計能使HDFS可擴展到最大的並發client數量。同時,namenode只不過提供塊的位置請求(存儲在內存中,十分高效),不是提供數據。否則如果客戶端數量增長,namenode就會快速成為一個“瓶頸”。

  注意:

    這里HdfsDataInputStream是FSDataInputStream的子類,這里是通過子類創建父類對象。

    

二、HDFS的寫入過程

  

  1)客戶端通過在DistributedFileSystem中調用create()來創建文件。

  2)DistributedFileSystem 使用RPC去調用namenode,在文件系統的命名空間創一個新的文件,沒有塊與之相聯系。

    namenode執行各種不同的檢查(這個文件存不存在,有沒有權限去寫,能不能存的下這個文件)以確保這個文件不會已經存在,並且在client有可以創建文件的適當的許可。

    如果檢查通過,namenode就會生成一個新的文件記錄;否則,文件創建失敗並向client拋出一個IOException異常。

      分布式文件系統返回一個文件系統數據輸出流,讓client開始寫入數據。就像讀取事件一樣,文件系統數據輸出流控制一個DFSOutputStream,負責處理datanode和namenode之間的通信。

  3)在client寫入數據時,DFSOutputStream將它分成一個個的包,寫入內部的隊列,成為數據隊列。數據隊列隨數據流流動,數據流的責任是根據適合的datanode的列表要求這些節點為副本分配新的塊。

     這個數據節點的列表形成一個管線——假設副本數是3,所以有3個節點在管線中。

  4)數據流將包分流給管線中第一個的datanode,這個節點會存儲包並且發送給管線中的第二個datanode。同樣地,第二個datanode存儲包並且傳給管線中的第三個數據節點。  

  5)DFSOutputStream也有一個內部的包隊列來等待datanode收到確認,成為確認隊列。一個包只有在被管線中所有的節點確認后才會被移除出確認隊列。如果在有數據寫入期間,datanode發生故障,

    則會執行下面的操作,當然這對寫入數據的client而言是透明的。首先管線被關閉,確認隊列中的任何包都會被添加回數據隊列的前面,以確保故障節點下游的datanode不會漏掉任意一個包。

   為存儲在另一正常datanode的當前數據塊制定一個新的標識,並將該標識傳給namenode,以便故障節點datanode在恢復后可以刪除存儲的部分數據塊。

   從管線中刪除故障數據節點並且把余下的數據塊寫入管線中的兩個正常的datanode。namenode注意到塊復本量不足時,會在另一個節點上創建一個新的復本。

   后續的數據塊繼續正常接收處理。只要dfs.replication.min的副本(默認是1)被寫入,寫操作就是成功的,並且這個塊會在集群中被異步復制,直到其滿足目標副本數(dfs.replication 默認值為3)。

  6)client完成數據的寫入后,就會在流中調用close()。

  7)在向namenode節點發送完消息之前,此方法會將余下的所有包放入datanode管線並等待確認。

   namenode節點已經知道文件由哪些塊組成(通過Data streamer 詢問塊分配),所以它只需在返回成功前等待塊進行最小量的復制。

  8)補充說明——復本的布局:Hadoop的默認布局策略是在運行客戶端的節點上放第1個復本(如果客戶端運行在集群之外,就隨機選擇一個節點,不過系統會避免挑選那些存儲太滿或太忙的節點。)

   第2個復本放在與第1個復本不同且隨機另外選擇的機架的節點上(離架)。第3個復本與第2個復本放在相同的機架,且隨機選擇另一個節點。其他復本放在集群中隨機的節點上,不過系統會盡量避免相同的機架放太多復本。

三、通過實例說明HDFS的讀寫操作

3.1、寫入操作

  

  前提:

    有一個文件FileA,100M大小。Client將FileA寫入到HDFS上。
    HDFS按默認配置。
    HDFS分布在三個機架上Rack1,Rack2,Rack3。

  步驟:

    1) Client將FileA按64M分塊。分成兩塊,block1和Block2;
    2) Client向nameNode發送寫數據請求,如圖藍色虛線①------>。
    3) NameNode節點,記錄block信息。並返回可用的DataNode,如粉色虛線②--------->。
      Block1: host2,host1,host3
      Block2: host7,host8,host4
      原理:
        NameNode具有RackAware機架感知功能,這個可以配置。
        若client為DataNode節點,那存儲block時,規則為:副本1,同client的節點上;副本2,不同機架節點上;副本3,同第二個副本機架的另一個節點上;其他副本隨機挑選。
        若client不為DataNode節點,那存儲block時,規則為:副本1,隨機選擇一個節點上;副本2,不同副本1,機架上;副本3,同副本2相同的另一個節點上;其他副本隨機挑選。
    4)client向DataNode發送block1;發送過程是以流式寫入。
      流式寫入過程:
        第一步:將64M的block1按64k的package划分;
        第二步:然后將第一個package發送給host2;
        第三步:host2接收完后,將第一個package發送給host1,同時client想host2發送第二個package;
        第四步:host1接收完第一個package后,發送給host3,同時接收host2發來的第二個package。
        第五步:以此類推,如圖紅線實線所示,直到將block1發送完畢。
        第六步:host2,host1,host3向NameNode,host2向Client發送通知,說“消息發送完了”。如圖粉紅顏色實線所示。
        第七步:client收到host2發來的消息后,向namenode發送消息,說我寫完了。這樣就真完成了。如圖黃色粗實線
        第八步:發送完block1后,再向host7,host8,host4發送block2,如圖藍色實線所示。
        第九步:發送完block2后,host7,host8,host4向NameNode,host7向Client發送通知,如圖淺綠色實線所示。
        第十步:client向NameNode發送消息,說我寫完了,如圖黃色粗實線。。。這樣就完畢了。

  分析:

    通過寫過程,我們可以了解到:
      1)寫1T文件,我們需要3T的存儲,3T的網絡流量貸款。
      2)在執行讀或寫的過程中,NameNode和DataNode通過HeartBeat進行保存通信,確定DataNode活着。
        如果發現DataNode死掉了,就將死掉的DataNode上的數據,放到其他節點去。讀取時,要讀其他節點去。
      3)掛掉一個節點,沒關系,還有其他節點可以備份;甚至,掛掉某一個機架,也沒關系;其他機架上,也有備份。

3.2、讀取操作

  

  讀操作就簡單一些了,如圖所示,client要從datanode上,讀取FileA。而FileA由block1和block2組成。 

  那么,讀操作流程為:
    1)client向namenode發送讀請求。
    2)namenode查看Metadata信息,返回fileA的block的位置。
      block1:host2,host1,host3
      block2:host7,host8,host4
    3)block的位置是有先后順序的,先讀block1,再讀block2。而且block1去host2上讀取;然后block2,去host7上讀取;
  上面例子中,client位於機架外,那么如果client位於機架內某個DataNode上,例如,client是host6。那么讀取的時候,遵循的規律是:優選讀取本機架上的數據。

四、圖解HDFS的讀取寫入過程

以簡潔易懂的漫畫形式講解HDFS存儲機制與運行原理

4.1、角色出演

  

  如上圖所示,HDFS存儲相關角色與功能如下:
    Client:客戶端,系統使用者,調用HDFS API操作文件;與NN交互獲取文件元數據;與DN交互進行數據讀寫。
    Namenode:元數據節點,是系統唯一的管理者。負責元數據的管理;與client交互進行提供元數據查詢;分配數據存儲節點等。
    Datanode:數據存儲節點,負責數據塊的存儲與冗余備份;執行數據塊的讀寫操作等。

4.2、讀取操作

  1)用戶需求 

    

    HDFS采用的是“一次寫入多次讀取”的文件訪問模型。一個文件經過創建、寫入和關閉之后就不需要改變。這一假設簡化了數據一致性問題,並且使高吞吐量的數據訪問成為可能。

  2)先聯系元數據節點

    

    

    

  3)下載數據

    

    數據存儲已經按照客戶端與DataNode節點之間的距離進行了排序,距客戶端越近的DataNode節點被放在最前面,客戶端會優先從本地讀取該數據塊。

3.2、寫入操作

  1)發送寫數據請求

    

    HDFS中的存儲單元是block。文件通常被分成64或128M一塊的數據塊進行存儲。與普通文件系統不同的是,在HDFS中,如果一個文件大小小於一個數據塊的大小,它是不需要占用整個數據塊的存儲空間的。

  2)文件切分

    

  3)DN分配

    

    

  4)數據寫入

    

    

  5)寫入完成

    

    

    

  6)角色定位

    

  

 


 -END-

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM