您好,登錄后才能下訂單哦!
一、HDFS基本概念
HDFS全稱是Hadoop Distributed System。HDFS是為以流的方式存取大文件而設計的。適用于幾百MB,GB以及TB,并寫一次讀多次的場合。而對于低延時數(shù)據(jù)訪問、大量小文件、同時寫和任意的文件修改,則并不是十分適合。
目前HDFS支持的使用接口除了Java的還有,Thrift、C、FUSE、WebDAV、HTTP等。HDFS是以block-sized chunk組織其文件內容的,默認的block大小為64MB,對于不足64MB的文件,其會占用一個block,但實際上不用占用實際硬盤上的64MB,這可以說是HDFS是在文件系統(tǒng)之上架設的一個中間層。之所以將默認的block大小設置為64MB這么大,是因為block-sized對于文件定位很有幫助,同時大文件更使傳輸?shù)臅r間遠大于文件尋找的時間,這樣可以最大化地減少文件定位的時間在整個文件獲取總時間中的比例。
二、HDFS設計原則
HDFS是Google的GFS(Google File System)的開源實現(xiàn)。具有以下五個基本目標:
1、硬件錯誤是常態(tài)而不是錯誤。HDFS一般運行在普通的硬件上,所以硬件錯誤是一種很正常的情況。所以在HDFS中,錯誤的檢測并快速自動恢復是HDFS的最核心的設計目標。
2、流式數(shù)據(jù)訪問。運行在HDFS上的應用主要是以批量處理為主,而不是用戶交互式事務,以流式數(shù)據(jù)讀取為多。
3、大規(guī)模數(shù)據(jù)集。HDFS中典型的文件大小要達到GB或者是TB級。
4、簡單一致性原則。HDFS的應用程序一般對文件的操作時一次寫入、多次讀出的模式。文件一經(jīng)創(chuàng)建、寫入、關閉后,一般文件內容再發(fā)生改變。這種簡單的一致性原則,使高吞吐量的數(shù)據(jù)訪問成為可能。
5、數(shù)據(jù)就近原則。HDFS提供接口,以便應用程序將自身的執(zhí)行代碼移動到數(shù)據(jù)節(jié)點上來執(zhí)行。采用這種方式的原因主要是:移動計算比移動數(shù)據(jù)更加劃算。相比與HDFS中的大數(shù)據(jù)/大文件,移動計算的代碼相比與移動數(shù)據(jù)更加劃算,采用這種方式可以提供寬帶的利用率,增加系統(tǒng)吞吐量,減少網(wǎng)絡的堵塞程度。
三、HDFS的體系結構
構成HDFS主要是Namenode(master)和一系列的Datanode(workers)。
Namenode是管理HDFS的目錄樹和相關的文件元數(shù)據(jù),這些信息是以"namespacep_w_picpath"和"edit log"兩個文件形式存放在本地磁盤,但是這些文件是在HDFS每次重啟的時候重新構造出來的。
Datanode則是存取文件實際內容的節(jié)點,Datanodes會定時地將block的列表匯報給Namenode。
由于Namenode是元數(shù)據(jù)存放的節(jié)點,如果Namenode掛了那么HDFS就沒法正常運行,因此一般使用將元數(shù)據(jù)持久存儲在本地或遠程的機器上,或者使用secondary namenode來定期同步Namenode的元數(shù)據(jù)信息,secondary namenode有點類似于MySQL的Master/Salves中的Slave,"edit log"就類似"bin log"。如果Namenode出現(xiàn)了故障,一般會將原Namenode中持久化的元數(shù)據(jù)拷貝到secondary namenode中,使secondary namenode作為新的Namenode運行起來。
HDFS是一個主從結構(master/slave)。如圖所示:
四、HDFS可靠性保障措施
HDFS的主要設計目標之一是在故障情況下,要保障數(shù)據(jù)存儲的可靠性。
HDFS具備了完善的冗余備份和故障恢復機制。一般通過dfs.replication設置備份份數(shù),默認3。
1、冗余備份。將數(shù)據(jù)寫入到多個DataNode節(jié)點上,當其中某些節(jié)點宕機后,還可以從其他節(jié)點獲取數(shù)據(jù)并復制到其他節(jié)點,使備份數(shù)達到設置值。dfs.replication設置備份數(shù)。
2、副本存放。HDFS采用機架感知(Rack-aware)的策略來改進數(shù)據(jù)的可靠性、可用性和網(wǎng)絡寬帶的利用率。當復制因子為3時,HDFS的副本存放策略是:第一個副本放到同一機架的另一個節(jié)點(執(zhí)行在集群中)/隨機一個節(jié)點(執(zhí)行在集群外)。第二個副本放到本地機架的其他任意節(jié)點。第三個副本放在其他機架的任意節(jié)點。這種策略可以防止整個機架失效時的數(shù)據(jù)丟失,也可以充分利用到機架內的高寬帶特效。
3、心跳檢測。NameNode會周期性的從集群中的每一個DataNode上接收心跳包和塊報告,NameNode根據(jù)這些報告驗證映射和其他文件系統(tǒng)元數(shù)據(jù)。當NameNode沒法接收到DataNode節(jié)點的心跳報告后,NameNode會將該DataNode標記為宕機,NameNode不會再給該DataNode節(jié)點發(fā)送任何IO操作。同時DataNode的宕機也可能導致數(shù)據(jù)的復制。一般引發(fā)重新復制副本有多重原因:DataNode不可用、數(shù)據(jù)副本損壞、DataNode上的磁盤錯誤或者復制因子增大。
4、安全模式。在HDFS系統(tǒng)的時候,會先經(jīng)過一個完全模式,在這個模式中,是不允許數(shù)據(jù)塊的寫操作。NameNode會檢測DataNode上的數(shù)據(jù)塊副本數(shù)沒有達到最小副本數(shù),那么就會進入完全模式,并開始副本的復制,只有當副本數(shù)大于最小副本數(shù)的時候,那么會自動的離開安全模式。DataNode節(jié)點有效比例:dfs.safemode.threshold.pct(默認0.999f),所以說當DataNode節(jié)點丟失達到1-0.999f后,會進入安全模式。
5、數(shù)據(jù)完整性檢測。HDFS實現(xiàn)了對HDFS文件內容的校驗和檢測(CRC循環(huán)校驗碼),在寫入數(shù)據(jù)文件的時候,也會將數(shù)據(jù)塊的校驗和寫入到一個隱藏文件中()。當客戶端獲取文件后,它會檢查從DataNode節(jié)點獲取的數(shù)據(jù)庫對應的校驗和是否和隱藏文件中的校驗和一致,如果不一致,那么客戶端就會認為該數(shù)據(jù)庫有損壞,將從其他DataNode節(jié)點上獲取數(shù)據(jù)塊,并報告NameNode節(jié)點該DataNode節(jié)點的數(shù)據(jù)塊信息。
6、回收站。HDFS中刪除的文件先會保存到一個文件夾中(/trash),方便數(shù)據(jù)的恢復。當刪除的時間超過設置的時間閥后(默認6小時),HDFS會將數(shù)據(jù)塊徹底刪除。
7、映像文件和事務日志。這兩種數(shù)據(jù)是HDFS中的核心數(shù)據(jù)結構。
8、快照。
五、數(shù)據(jù)存儲操作
1、數(shù)據(jù)存儲: block
默認數(shù)據(jù)塊大小為128MB,可配置。若文件大小不到128MB,則單獨存成一個block。
為何數(shù)據(jù)塊如此之大? 數(shù)據(jù)傳輸時間超過尋道時間(高吞吐率)
一個文件存儲方式? 按大小被切分成若干個block,存儲到不同節(jié)點上,默認情況下每個block有三個副本。
2、數(shù)據(jù)存儲: staging
HDFSclient上傳數(shù)據(jù)到HDFS時,首先,在本地緩存數(shù)據(jù),當數(shù)據(jù)達到一個block大小時,請求NameNode分配一個block。 NameNode會把block所在的DataNode的地址告訴HDFS client。 HDFS client會直接和DataNode通信,把數(shù)據(jù)寫到DataNode節(jié)點一個block文件中。
六、寫入數(shù)據(jù)
1.初始化FileSystem,客戶端調用create()來創(chuàng)建文件。
2.FileSystem用RPC調用元數(shù)據(jù)節(jié)點,在文件系統(tǒng)的命名空間中創(chuàng)建一個新的文件,元數(shù)據(jù)節(jié)點首先確定文件原來不存在,并且客戶端有創(chuàng)建文件的權限,然后創(chuàng)建新文件。
3.FileSystem返回DFSOutputStream,客戶端用于寫數(shù)據(jù),客戶端開始寫入數(shù)據(jù)。
4.DFSOutputStream將數(shù)據(jù)分成塊,寫入data queue。data queue由Data Streamer讀取,并通知元數(shù)據(jù)節(jié)點分配數(shù)據(jù)節(jié)點,用來存儲數(shù)據(jù)塊(每塊默認復制3塊)。分配的數(shù)據(jù)節(jié)點放在一個pipeline里。Data Streamer將數(shù)據(jù)塊寫入pipeline中的第一個數(shù)據(jù)節(jié)點。第一個數(shù)據(jù)節(jié)點將數(shù)據(jù)塊發(fā)送給第二個數(shù)據(jù)節(jié)點。第二個數(shù)據(jù)節(jié)點將數(shù)據(jù)發(fā)送給第三個數(shù)據(jù)節(jié)點。
5.DFSOutputStream為發(fā)出去的數(shù)據(jù)塊保存了ack queue,等待pipeline中的數(shù)據(jù)節(jié)點告知數(shù)據(jù)已經(jīng)寫入成功。
6.當客戶端結束寫入數(shù)據(jù),則調用stream的close函數(shù)。此操作將所有的數(shù)據(jù)塊寫入pipeline中的數(shù)據(jù)節(jié)點,并等待ack queue返回成功。最后通知元數(shù)據(jù)節(jié)點寫入完畢。
7.如果數(shù)據(jù)節(jié)點在寫入的過程中失敗,關閉pipeline,將ack queue中的數(shù)據(jù)塊放入data queue的開始,當前的數(shù)據(jù)塊在已經(jīng)寫入的數(shù)據(jù)節(jié)點中被元數(shù)據(jù)節(jié)點賦予新的標示,則錯誤節(jié)點重啟后能夠察覺其數(shù)據(jù)塊是過時的,會被刪除。失敗的數(shù)據(jù)節(jié)點從pipeline中移除,另外的數(shù)據(jù)塊則寫入pipeline中的另外兩個數(shù)據(jù)節(jié)點。元數(shù)據(jù)節(jié)點則被通知此數(shù)據(jù)塊是復制塊數(shù)不足,將來會再創(chuàng)建第三份備份。
8.如果在寫的過程中某個datanode發(fā)生錯誤,會采取以下幾步:
1)pipeline被關閉掉;
2)為了防止防止丟包ack quene里的packet會同步到data quene里;
3)把產(chǎn)生錯誤的datanode上當前在寫但未完成的block刪掉;
4)block剩下的部分被寫到剩下的兩個正常的datanode中;
5)namenode找到另外的datanode去創(chuàng)建這個塊的復制。當然,這些操作對客戶端來說是無感知的。
Java代碼
Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(conf); Path file = new Path("demo.txt"); FSDataOutputStream outStream =fs.create(file); outStream.writeUTF("Welcome to HDFSJava API!!!"); outStream.close();
寫入過程圖片:
七、讀取過程
1.初始化FileSystem,然后客戶端(client)用FileSystem的open()函數(shù)打開文件。
2.FileSystem用RPC調用元數(shù)據(jù)節(jié)點,得到文件的數(shù)據(jù)塊信息,對于每一個數(shù)據(jù)塊,元數(shù)據(jù)節(jié)點返回保存數(shù)據(jù)塊的數(shù)據(jù)節(jié)點的地址。
3.FileSystem返回FSDataInputStream給客戶端,用來讀取數(shù)據(jù),客戶端調用stream的read()函數(shù)開始讀取數(shù)據(jù)。
4.DFSInputStream連接保存此文件第一個數(shù)據(jù)塊的最近的數(shù)據(jù)節(jié)點,data從數(shù)據(jù)節(jié)點讀到客戶端(client)
5.當此數(shù)據(jù)塊讀取完畢時,DFSInputStream關閉和此數(shù)據(jù)節(jié)點的連接,然后連接此文件下一個數(shù)據(jù)塊的最近的數(shù)據(jù)節(jié)點。
6.當客戶端讀取完畢數(shù)據(jù)的時候,調用FSDataInputStream的close函數(shù)。
7.在讀取數(shù)據(jù)的過程中,如果客戶端在與數(shù)據(jù)節(jié)點通信出現(xiàn)錯誤,則嘗試連接包含此數(shù)據(jù)塊的下一個數(shù)據(jù)節(jié)點。
8. 失敗的數(shù)據(jù)節(jié)點將被記錄,以后不再連接。
Java代碼
Configurationconf = new Configuration(); FileSystemfs = FileSystem.get(conf); Pathfile = new Path("demo.txt"); FSDataInputStreaminStream = fs.open(file); Stringdata = inStream.readUTF(); System.out.println(data); inStream.close();
讀取文件過程圖片:
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。