HDFS之四:HDFS原理解析(總體架構,讀寫操作流程)


前言

HDFS 是一個能夠面向大規模數據使用的,可進行擴展的文件存儲與傳遞系統。是一種允許文件通過網絡在多台主機上分享的文件系統,可讓多機器上的多用戶分享文件和 存儲空間。讓實際上是通過網絡來訪問文件的動作,由程序與用戶看來,就像是訪問本地的磁盤一般。即使系統中有某些節點脫機,整體來說系統仍然可以持續運作 而不會有數據損失。

一、HDFS體系結構

技術分享

1、Namenode 

Namenode是整個文件系統的管理節點。它維護着整個文件系統的文件目錄樹,文件/目錄的元信息和每個文件對應的數據塊列表, 接收用戶的操作請求。 
文件包括: 
①fsimage:元數據鏡像文件。存儲某一時段NameNode內存元數據信息。 
②edits:操作日志文件。 
③fstime:保存最近一次checkpoint的時間 
以上這些文件是保存在linux的文件系統中。通過hdfs-site.xml的dfs.namenode.name.dir屬性進行設置。

查看NameNode的fsimage與edits內容 
這個兩個文件中的內容使用普通文本編輯器是無法直接查看的,幸運的是hadoop為此准備了專門的工具用於查看文件的內容,這些工具分別為oev和oiv,可以使用hdfs調用執行。

啟動服務器:bin/hdfs oiv -i 某個fsimage文件

bash$ bin/hdfs oiv -i fsimage 
14/04/07 13:25:14 INFO offlineImageViewer.WebImageViewer: WebImageViewer started. 
Listening on /127.0.0.1:5978. Press Ctrl+C to stop the viewer.

查看內容:bin/hdfs dfs -ls -R webhdfs://127.0.0.1:5978/

bash$ bin/hdfs dfs -ls webhdfs://127.0.0.1:5978/ 
Found 2 items 
drwxrwx–* - root supergroup 0 2014-03-26 20:16 webhdfs://127.0.0.1:5978/tmp 
drwxr-xr-x - root supergroup 0 2014-03-31 14:08 webhdfs://127.0.0.1:5978/user

導出fsimage的內容:bin/hdfs oiv -p XML -i 
tmp/dfs/name/current/fsimage_0000000000000000055 -o fsimage.xml

bash$ bin/hdfs oiv -p XML -i fsimage -o fsimage.xml 
0000055 -o fsimage.xml

查看edtis的內容:bin/hdfs oev -i 
tmp/dfs/name/current/edits_0000000000000000057-0000000000000000186 -o edits.xml

bash$ bin/hdfs oev -i 
tmp/dfs/name/current/edits_0000000000000000057-0000000000000000186 -o edits.xml

元信息的持久化

在NameNode中存放元信息的文件是 fsimage。在系統運行期間所有對元信息的操作都保存在內存中並被持久化到另一個文件edits中。並且edits文件和fsimage文件會被SecondaryNameNode周期性的合並(合並過程會在SecondaryNameNode中詳細介紹)。

NameNode特點

運行NameNode會占用大量內存和I/O資源,一般NameNode不會存儲用戶數據或執行MapReduce任務。

為了簡化系統的設計,Hadoop只有一個NameNode,這也就導致了hadoop集群的單點故障問題。因此,對NameNode節點的容錯尤其重要,hadoop提供了如下兩種機制來解決:

  • 將hadoop元數據寫入到本地文件系統的同時再實時同步到一個遠程掛載的網絡文件系統(NFS)。
  • 運行一個secondary NameNode,它的作用是與NameNode進行交互,定期通過編輯日志文件合並命名空間鏡像,當NameNode發生故障時它會通過自己合並的命名空間鏡像副本來恢復。需要注意的是secondaryNameNode保存的狀態總是滯后於NameNode,所以這種方式難免會導致丟失部分數據(后面會詳細介紹)。

SecondaryNameNode

需要注意,SecondaryNameNode並不是NameNode的備份。我們從前面的介紹已經知道,所有HDFS文件的元信息都保存在NameNode的內存中。在NameNode啟動時,它首先會加載fsimage到內存中,在系統運行期間,所有對NameNode的操作也都保存在了內存中,同時為了防止數據丟失,這些操作又會不斷被持久化到本地edits文件中。

edits文件存在的目的是為了提高系統的操作效率,NameNode在更新內存中的元信息之前都會先將操作寫入edits文件。在NameNode重啟的過程中,edits會和fsimage合並到一起,但是合並的過程會影響到Hadoop重啟的速度,SecondaryNameNode就是為了解決這個問題而誕生的。

SecondaryNameNode的角色就是定期的合並edits和fsimage文件,我們來看一下合並的步驟:

  1. 合並之前告知NameNode把所有的操作寫到新的edites文件並將其命名為edits.new。
  2. SecondaryNameNode從NameNode請求fsimage和edits文件
  3. SecondaryNameNode把fsimage和edits文件合並成新的fsimage文件
  4. NameNode從SecondaryNameNode獲取合並好的新的fsimage並將舊的替換掉,並把edits用第一步創建的edits.new文件替換掉
  5. 更新fstime文件中的檢查點

最后再總結一下整個過程中涉及到NameNode中的相關文件

  • fsimage :保存的是上個檢查點的HDFS的元信息
  • edits :保存的是從上個檢查點開始發生的HDFS元信息狀態改變信息
  • fstime:保存了最后一個檢查點的時間戳

2、Datanode

提供真實文件數據的存儲服務。 DataNode是hdfs中的worker節點,它負責存儲數據塊,也負責為系統客戶端提供數據塊的讀寫服務,同時還會根據NameNode的指示來進行創建、刪除、和復制等操作。此外,它還會通過心跳定期向NameNode發送所存儲文件塊列表信息。當對hdfs文件系統進行讀寫時,NameNode告知客戶端每個數據駐留在哪個DataNode,客戶端直接與DataNode進行通信,DataNode還會與其它DataNode通信,復制這些塊以實現冗余

文件塊( block): 最基本的存儲單位。 
對於文件內容而言,一個文件的長度大小是size,那么從文件的0偏移開始,按照固定的大小,順序對文件進行划分並編號,划分好的每一個塊稱一個Block。 HDFS默認Block大小是128MB, 因此,一個256MB文件,共有256/128=2個Block. 
與普通文件系統不同的是,在 HDFS中,如果一個文件小於一個數據塊的大小,並不占用整個數據塊存儲空間。 
Replication:多復本。默認是三個。通過hdfs-site.xml的dfs.replication屬性進行設置。

二、數據備份

HDFS通過備份數據塊的形式來實現容錯,除了文件的最后一個數據塊外,其它所有數據塊大小都是一樣的。數據塊的大小和備份因子都是可以配置的。NameNode負責各個數據塊的備份,DataNode會通過心跳的方式定期的向NameNode發送自己節點上的Block 報告,這個報告中包含了DataNode節點上的所有數據塊的列表

文件副本的分布位置直接影響着HDFS的可靠性和性能。一個大型的HDFS文件系統一般都是需要跨很多機架的,不同機架之間的數據傳輸需要經過網關,並且,同一個機架中機器之間的帶寬要大於不同機架機器之間的帶寬。如果把所有的副本都放在不同的機架中,這樣既可以防止機架失敗導致數據塊不可用,又可以在讀數據時利用到多個機架的帶寬,並且也可以很容易的實現負載均衡。但是,如果是寫數據,各個數據塊需要同步到不同的機架,會影響到寫數據的效率。

而在Hadoop中,如果副本數量是3的情況下,Hadoop默認是這么存放的,把第一個副本放到機架的一個節點上,另一個副本放到同一個機架的另一個節點上,把最后一個節點放到不同的機架上。這種策略減少了跨機架副本的個數提高了寫的性能,也能夠允許一個機架失敗的情況,算是一個很好的權衡。

關於副本的選擇,在讀的過程中,HDFS會選擇最近的一個副本給請求者。

三、HDFS中的溝通協議

  所有的HDFS中的溝通協議都是基於tcp/ip協議,一個客戶端通過指定的tcp端口與NameNode機器建立連接,並通過ClientProtocol協議與NameNode交互。而DataNode則通過DataNode Protocol協議與NameNode進行溝通。HDFS的RCP(遠程過程調用)對ClientProtocol和DataNode Protocol做了封裝。按照HDFS的設計,NameNode不會主動發起任何請求,只會被動接受來自客戶端或DataNode的請求。

四、可靠性保證

可以允許DataNode失敗。DataNode會定期(默認3秒)的向NameNode發送心跳,若NameNode在指定時間間隔內沒有收到心跳,它就認為此節點已經失敗。此時,NameNode把失敗節點的數據(從另外的副本節點獲取)備份到另外一個健康的節點。這保證了集群始終維持指定的副本數。

可以檢測到數據塊損壞。在讀取數據塊時,HDFS會對數據塊和保存的校驗和文件匹配,如果發現不匹配,NameNode同樣會重新備份損壞的數據塊。

五、數據存儲操作過程剖析

1、數據存儲: block 
默認數據塊大小為128MB,可配置。若文件大小不到128MB,則單獨存成一個block。 
為何數據塊如此之大? 
數據傳輸時間超過尋道時間(高吞吐率) 
一個文件存儲方式? 
按大小被切分成若干個block,存儲到不同節點上,默認情況下每個block有三個副本。 
技術分享 
HDFS Block的設計理念:一個文件由哪些塊組成。一個塊存儲在哪些節點上。好處:易於分攤到各個節點。如下:

block1:node1,node2,node3 
block2:node2,node3,node4 
block3:node4,mode5,node6 
block4:node5,node6.node7

2、數據存儲: staging 
HDFS client上傳數據到HDFS時,首先,在本地緩存數據,當數據達到一個block大小時,請求NameNode分配一個block。 NameNode會把block所在的DataNode的地址告訴HDFS client。 HDFS client會直接和DataNode通信,把數據寫到DataNode節點一個block文件中。

3、數據存儲:讀文件操作 
技術分享 
1.首先調用FileSystem對象的open方法,其實是一個DistributedFileSystem的實例。

2.DistributedFileSystem通過rpc獲得文件的第一批block的locations,同一個block按照重復數會返回多個locations,這些locations按照hadoop拓撲結構排序,距離客戶端近的排在前面。

3.前兩步會返回一個FSDataInputStream對象,該對象會被封裝DFSInputStream對象,DFSInputStream可 以方便的管理datanode和namenode數據流。客戶端調用read方法,DFSInputStream最會找出離客戶端最近的datanode 並連接。

4.數據從datanode源源不斷的流向客戶端。

5.如果第一塊的數據讀完了,就會關閉指向第一塊的datanode連接,接着讀取下一塊。這些操作對客戶端來說是透明的,客戶端的角度看來只是讀一個持續不斷的流。

6.如果第一批block都讀完了, DFSInputStream就會去namenode拿下一批block的locations,然后繼續讀,如果所有的塊都讀完,這時就會關閉掉所有的流。 
如果在讀數據的時候, DFSInputStream和datanode的通訊發生異常,就會嘗試正在讀的block的排序第二近的datanode,並且會記錄哪個 datanode發生錯誤,剩余的blocks讀的時候就會直接跳過該datanode。 DFSInputStream也會檢查block數據校驗和,如果發現一個壞的block,就會先報告到namenode節點,然后 DFSInputStream在其他的datanode上讀該block的鏡像。

該設計就是客戶端直接連接datanode來檢索數據並且namenode來負責為每一個block提供最優的datanode, namenode僅僅處理block location的請求,這些信息都加載在namenode的內存中,hdfs通過datanode集群可以承受大量客戶端的並發訪問。

六、數據存儲:寫文件操作剖析

 技術分享

1.客戶端通過調用DistributedFileSystem的create方法創建新文件。

2.DistributedFileSystem通過RPC調用namenode去創建一個沒有blocks關聯的新文件,創建前, namenode會做各種校驗,比如文件是否存在,客戶端有無權限去創建等。如果校驗通過, namenode就會記錄下新文件,否則就會拋出IO異常。

3.前兩步結束后,會返回FSDataOutputStream的對象,與讀文件的時候相似, FSDataOutputStream被封裝成DFSOutputStream。DFSOutputStream可以協調namenode和 datanode。客戶端開始寫數據到DFSOutputStream,DFSOutputStream會把數據切成一個個小的packet,然后排成隊 列data quene。

4.DataStreamer會去處理接受data quene,它先詢問namenode這個新的block最適合存儲的在哪幾個datanode里(比如重復數是3,那么就找到3個最適合的 datanode),把他們排成一個pipeline。DataStreamer把packet按隊列輸出到管道的第一個datanode中,第一個 datanode又把packet輸出到第二個datanode中,以此類推。

5.DFSOutputStream還有一個對列叫ack quene,也是由packet組成,等待datanode的收到響應,當pipeline中的所有datanode都表示已經收到的時候,這時akc quene才會把對應的packet包移除掉。 
如果在寫的過程中某個datanode發生錯誤,會采取以下幾步: 
1) pipeline被關閉掉; 
2)為了防止防止丟包ack quene里的packet會同步到data quene里; 
3)把產生錯誤的datanode上當前在寫但未完成的block刪掉; 
4)block剩下的部分被寫到剩下的兩個正常的datanode中; 
5)namenode找到另外的datanode去創建這個塊的復制。當然,這些操作對客戶端來說是無感知的。

6.客戶端完成寫數據后調用close方法關閉寫入流。

7.DataStreamer把剩余得包都刷到pipeline里,然后等待ack信息,收到最后一個ack后,通知datanode把文件標視為已完成。

注意:客戶端執行write操作后,寫完的block才是可見的,正在寫的block對客戶端是不可見的,只有 調用sync方法,客戶端才確保該文件的寫操作已經全部完成,當客戶端調用close方法時,會默認調用sync方法。是否需要手動調用取決你根據程序需 要在數據健壯性和吞吐率之間的權衡。

七、hdfs文件刪除過程

hdfs文件刪除過程一般需要如下幾步:

1. 一開始刪除文件,NameNode只是重命名被刪除的文件到/trash目錄,因為重命名操作只是元信息的變動,所以整個過程非常快。在/trash中文件會被保留一定間隔的時間(可配置,默認是6小時),在這期間,文件可以很容易的恢復,恢復只需要將文件從/trash移出即可。
2. 當指定的時間到達,NameNode將會把文件從命名空間中刪除
3. 標記刪除的文件塊釋放空間,HDFS文件系統顯示空間增加


免責聲明!

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



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