1. 程式人生 > 其它 >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

2、Datanode
提供真實檔案資料的儲存服務。
檔案塊( block): 最基本的儲存單位。
對於檔案內容而言,一個檔案的長度大小是size,那麼從檔案的0偏移開始,按照固定的大小,順序對檔案進行劃分並編號,劃分好的每一個塊稱一個Block。 HDFS預設Block大小是128MB, 因此,一個256MB檔案,共有256/128=2個Block.
與普通檔案系統不同的是,在 HDFS中,如果一個檔案小於一個數據塊的大小,並不佔用整個資料塊儲存空間。
Replication:多複本。預設是三個。通過hdfs-site.xml的dfs.replication屬性進行設定。

二、資料儲存操作

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叢集可以承受大量客戶端的併發訪問。

4、資料儲存:寫檔案操作

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方法。是否需要手動呼叫取決你根據程式需 要在資料健壯性和吞吐率之間的權衡。