HDFS文件寫入與讀取

HDFS文件寫入與讀寫


副本(3個)選擇策略說明

1. 若client爲DataNode節點,那存儲block時,規則爲:副本1,同client的節點上;副本2,不同機架節點上;副本3,同第二個副本機架的另一個節點上;其他副本隨機挑選。

2. 若client不爲DataNode節點,那存儲block時,規則爲:副本1,隨機選擇一個節點上;副本2,不同副本1,機架上;副本3,同副本2相同的另一個節點上;其他副本隨機挑選。

 

將一個100M的文件上傳到HDFS中,Hadoop集羣如上圖所示的三個Rack,8個DataNode節點,集羣配置採用默認配置。HDFS數據塊的默認大小爲64M,則該文件被分爲兩個BLOCK進行寫入:Block1(64M)和Block2(36M)。

HadoopClient向集羣中的NameNode請求文件的寫入(圖中紅色實線)

NameNode節點接收到寫入請求,記錄block信息,並返回可用的DataNode節點。比如: Block1 : DataNode1——DataNode2——DataNode5

Block2 : DataNode4——DataNode3——DataNode6

需要說明的是:

(1) 如果上傳本機不是一個datanode,而是一個客戶端,那麼就從所有slave機器中隨機選擇一臺datanode作爲第一個塊的寫入機器(datanode1)。

而此時如果上傳機器本身就是一個datanode(例如mapreduce作業中task通過DFSClient向hdfs寫入數據的時候),那麼就將該datanode本身作爲第一個塊寫入機器(datanode1)。

(2) 隨後在datanode1所屬的機架以外的另外的機架上,隨機的選擇一臺,作爲第二個block的寫入datanode機器(datanode2)。

  (3) 在寫第三個block前,先判斷前兩個datanode是否是在同一個機架上,如果是在同一個機架,那麼就嘗試在另外一個機架上選擇第 三個datanode作爲寫入機器(datanode3)。而如果datanode1和datanode2沒有在同一個機架上,則在datanode2所 在的機架上選擇一臺datanode作爲datanode3。

 

Client接受到NameNode發送的可用DataNode列表(各個DataNode有排序,後面說明)之後,開始用流式的方式發送文件的Block,過程如下:


1 > 將block1(64M)劃分爲64k的packet;

2 > 然後Client將第一個64k的packet發送給DataNode1;

3 > DataNode1接收完後,將第一個packet發送給DataNode2,同時client向DataNode1發送第二個64k的packet;

4 > DataNode2接收完第一個packet後,發送給DataNode5,同時接收DataNode1發來的第二個packet;

5 > 以此類推,直到將block1發送完畢;

6 > DataNode1,DataNode2,DataNode5向NameNode發送“已完成”消息,DataNode1同時向Client發送完成通知;

7 > client收到DataNode1發來的消息後,向NameNode發送消息,表示已完成寫入。

8 > 發送完block1後,再向DataNode4、DataNode3、DataNode6發送Block2,以此類推。

對③的說明

NameNode根據Client的寫入請求選取可用的DataNode節點,在NameNode返回該DataNode列表到客戶端Client之前,會在NameNode端根據該寫入客戶端跟 DataNode列表中每個DataNode之間的“距離”由近到遠進行一個排序。如果此時寫入端不是DataNode,則選擇DataNode列 表中的第一個排在第一位。客戶端根據這個順序有近到遠的進行數據塊的寫入。在此,判斷兩個DataNode之間“距離”的算法就比較關鍵,hadoop目前距離計算如下:


每個DataNode都會對應自己在集羣中的位置和層次,如n1的位置信息爲“/r1/n1”,那麼它所處的層次就爲2,其餘類推。得到兩個node的層次後,會沿着每個node所處的拓樸樹中的位置向上查找,如“/r1/n1”的上一級就是“ /r1”,此時兩個節點之間的距離加1,兩個node分別同上向上查找,直到找到共同的祖先節點位置,此時所得的距離數就用來代表兩個節點之間的距離。如上圖所示,n2與藍色所示DataNode(命名爲node)之間的距離就爲2(因爲node/r1/node,而n2/r1/n2,,爲了找到相同的祖先節點,二者需要各自向上級查找1位,即找到共同祖先節點爲r1,則1+1=2),而n3則爲4(同理)。

 

如下圖所示爲從源碼角度對HDFS文件寫入的程序控制流程的描述:

 

(1) 客戶端通過調用DistributedFileSystem的create方法創建新文件。
(2)DistributedFileSystem通過RPC調用namenode去創建一個沒有blocks關聯的新文件,創建前,namenode會做各種校驗,比如文件是否存在,客戶端有無權限去創建等。如果校驗通過,namenode就會記錄下新文件,否則就會拋出IO異常。
(3)前兩步結束後會返回FSDataOutputStream的對象,和讀文件的時候相似,FSDataOutputStream被封裝成DFSOutputStream,DFSOutputStream可以協調namenode和datanode。客戶端開始寫數據到DFSOutputStreamDFSOutputStream會把數據切成一個個小packet,然後排成隊列data quene
(4)DataStreamer會去處理接受data quene,他先問詢namenode這個新的block最適合存儲的在哪幾個datanode裏,比如重複數是3,那麼就找到3個最適合的datanode,把他們排成一個pipeline。DataStreamerpacket按隊列輸出到管道的第一個datanode中,第一個datanode又把packet輸出到第二個datanode中,以此類推。
(5)DFSOutputStream還有一個對列叫ack quene,也是有packet組成,等待datanode的收到響應,當pipeline中的所有datanode都表示已經收到的時候,這時akc quene纔會把對應的packet包移除掉。
(6)客戶端完成寫數據後調用close方法關閉寫入流
(7)DataStreamer把剩餘得包都刷到pipeline裏然後等待ack信息,收到最後一個ack後,通知datanode把文件標示爲已完成。

補充:讀取數據

 當對某個文件的某個block進行讀取的時候,hadoop採取的策略也是一樣:

  1.首先得到這個block所在的datanode的列表,有幾個副本數該列表就有幾個datanode。

  2.根據列表中datanode距離讀取端的距離進行從小到大的排序:

  a)首先查找本地是否存在該block的副本,如果存在,則將本地datanode作爲第一個讀取該block的datanode

  b)然後查找本地的同一個rack下是否有保存了該block副本的datanode

  c)最後如果都沒有找到,或者讀取數據的node本身不是datanode節點,則返回datanode列表的一個隨機順序。

 

 

 

參考資料:http://bbs.chinahadoop.cn/forum.php?mod=viewthread&tid=5673&fromuid=696

http://blog.csdn.net/luyee2010/article/details/8622964

http://blog.csdn.net/woshiwanxin102213/article/det

http://bbs.superwu.cn/forum.php?mod=viewthread&tid=260&extra=page=2

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章