Hadoop分佈式文件系統HDFS

HDFS的探究:java

HDFS

HDFS是 Hadoop Distribute File System的縮寫,是谷歌GFS分佈式文件系統的開源實現,Apache Hadoop的一個子項目,HDFS基於流數據訪問模式的分佈式文件系統,支持海量數據的存儲,容許用戶將百千臺組成存儲集羣,HDFS運行在低成本的硬件上,提供高吞吐量,高容錯性的數據訪問。node

優勢

  • 能夠處理超大文件(TB、PB)。
  • 流式數據訪問 一次寫入屢次讀取,數據集一旦生成,會被複制分發到不一樣存儲節點上,響應各類數據分析任務請求。
  • 商用硬件 能夠運行在低廉的商用硬件集羣上。
  • 異構軟硬件平臺的可移植性,HDFS在設計的時候就考慮到了平臺的能夠移植性,這種特性方便了 HDFS在大規模數據應用平臺的推廣。

缺點

  • 低延遲的數據訪問,要求地時間延遲數據訪問的應用不是在HDFS上運行,能夠用Hbase,高吞吐量的同時會以提升時間延遲爲代價。
  • 大量小文件 因爲namenode將文件的元數據存儲在內存中,所以受制於namenode的內存容量,通常來講目錄塊和數據庫的存儲信息約佔150個字節也就是說若是有100萬個文件,每個文件佔一個數據塊,則須要300MB內存,可是存儲十億個就超出了當前的硬件能力了。
  • 多用戶寫入,任意修改文件。HDFS中的文件寫入只支持一個用戶,且只能以添加的方式正在文件末尾添加數據,不支持多個寫操做,不支持文件的任意位置修改。

數據塊

HDFS默認的塊大小是128M,與單一磁盤上的文件系統類似,HDFS也被劃分爲塊大小的多個分塊。HDFS中小於一個塊大小的文件不會佔據整個塊的空間,當一個1M的文件存儲在一個128M的塊中時,文件只佔1M的磁盤空間,而不是128M。HDFS的塊比磁盤的塊大,目的時爲了最小化的尋址開銷,假設尋址時間約爲10ms,傳輸速度爲100M/s,爲了使尋址時間僅佔傳輸時間的1%,咱們要將塊設置成100MB,默認塊的大小爲128M,這個塊的大小也不能設置得過大。MapReduce中的map任務一般一次只處理一個數據塊的數據,所以若是任務數量太少了(少於集羣中的節點數量),做業的運行速度就會比較慢。python

NameNode

元數據節點(NameNode)的做用是管理分佈式文件的命名空間,一個集羣只有一個NameNode節點,主要負責HDFS文件系統的管理工做包括命名空間管理和文件Block管理,在HDFS內部,一個文件被分紅爲一個或者多個Block的全部元數據信息,主要包括「文件名 —>>數據塊的映射「,」數據塊 —>>DataNode「的映射列表,該列表經過DataNode上報給NameNode創建,NameNode決定文件數據塊到具體的DataNode節點的映射。數據庫

NameNode管理文件系統的命名空間(namespace),它維護這文件系統樹以及文件樹中全部的文件(文件夾)的元數據。管理這些信息的文件有兩個,分別是命名空間鏡像文件(namespace image)和操做日誌文件(edit log),這些信息被緩存在RAM中,也會持被持久化存儲在硬盤。apache

爲了周其性地將元數據節點地鏡像文件fsimage和日誌edits合併,以防止日誌文件過大,HDFS定義了輔助元數據節點(Secondary NameNode)上也保存了一份fsimage文件,以確保在元數據文件中地鏡像文件失敗時能夠恢復。緩存

容錯機制

NFS

備份組成文件系統元數據持久狀態的文件,將本地持久狀態寫入磁盤地同時,寫入一個遠程掛載地文件系統(NFS)安全

輔助節點

運行一個輔助的Namenode,不做爲Namenode使用,按期合併編輯日誌和命名空間鏡像,通常在一臺單獨的物理計算機上運行,由於它須要佔用大量CPU時間,而且須要與namenode同樣多的內存來執行合併操做,會保存Namenode合併後的命名空間和鏡像文件,通常會滯後於NameNode節點的。服務器

RAID

使用磁盤陳列NameNode節點上冗餘備份Namenode的數據。網絡

DataNode

數據節點只負責存儲數據,一個Block會在多個DataNode中進行冗餘備份,一個塊在一個DataNode上最多隻有一個備份,DataNode上存儲了數據塊ID和數據塊內容以及他們的映射關係。負載均衡

DataNode定時和NameNode通訊,接收NameNode的指令,默認的超時時長爲10分鐘+30s。 NameNode上不永久保存DataNode上有哪些數據塊信息,經過DataNode上報的方式更新NameNode上的映射表,DataNode和NameNode創建鏈接後,會不斷和 NameNode保持聯繫,包括NameNode第DataNode的一些命令,如刪除數據或把數據塊複製到另外一個DataNode上等,DataNode一般以機架的形式組織,機架經過一個交互機將全部的系統連接起來。機架內部節點之間傳輸速度快於機架間節點的傳輸速度。

DataNode同時做爲服務器接收客戶端的範圍呢,處理數據塊的讀、寫請求。DataNode之間還會相互他通訊,執行數據塊複製任務,在數據塊複製任務,在客戶端執行寫操做時,DataNode之間須要相互通訊配合,保持寫操做的一致性,DataNode的功能包括:

  1. 保存Block,每一個塊對應原數據信息文件,描述這個塊屬於那個文件,第幾個塊等信息。
  2. 啓動DataNode線程,向NameNode按期彙報Block信息。
  3. 按期向NameNode發送心跳保持聯繫。若是10分鐘沒有接收到心跳,則認爲其lost,將其上的Block複製到其餘DataNode節點上。

SecondaryNameNode

SecondaryNameNode按期地建立命名空間地檢查點。首先從NameNode下載fsimage和edit.log而後在本地合併他們,將合併後地fsimage和edit.log上傳回到NameNode,這樣減小了NameNode從新啓動NameNode時合併fsimage和edits.log花費地時間,按期合併fsimage和edit.log文件,使得edits.log大小保持在限定返回內並起到冷備份的做用,在NameNode失效的時候,能夠恢復fsimage。SecondaryNameNode與NameNode一般運行在不一樣的機器上,內存呢與NameNode的內存同樣大。

參數dfs.namenode.secondary.http-address設置SecondaryNamenode 的通訊地址,SecondaryNamenode上的檢查點進程開始由兩個配置參數控制,第一個參數dfs.namenode.checkpoint.period,指定兩個連續檢查點之間的時間差默認1小時。dfs.namenode.checkpoint.txns,定義NameNode上新增事務的數量默認1百萬條。即便沒有到達設定的時間也會啓動fsimage和edits的合併。

工做流程

  1. SecondaryNameNode會按期和NameNode通訊,請求其中止使用edits文件,暫時將更新的操做寫道一個新的文件edits.new上來。這個操做時瞬間完成的,上層寫日誌的函數時徹底趕不到差異。

  2. SecondaryNameNode經過HTTP GET的方式從NameNode上獲取fsimage和edits.log文件,並下載到相應的目錄下。

  3. SecondaryNameNode將下載下來的fsimage載入到內存,而後一條一條的執行edits文件中的哥哥更新操做,使內存中的fsimage保持最新;這個過程就是edits和fsimage文件合併。

  4. SecondaryNameNode 執行完3操做後,會經過POST的方式新的fsimage文件發送到NameNode節點上。

  5. Namenode從SecondaryNameNode接收到更新的fsimage替換舊的fsimage文件,同時將edits.new改名爲edits文件,這個過程當中edits就變小了。

HDFS工做機制

機架感知

在HDFS中,數據塊被複製成副本,存放在不一樣的節點上,副本的存放是HDFS可靠性和性能的關鍵,優化副本存放策略使HDFS區分於其餘大部分分佈式文件系統的共同要特徵,HDFS採用了一種稱爲機架感知的(rck-aware)的策略來改進數據的可靠性,可用性和網絡帶寬的利用率。HDFS實例通常運行在多個機架的計算機組成的集羣上,不一樣機架上的兩臺機器之間的通訊時經過交互機。在多數狀況下,一個機架上的兩臺機器間的帶寬會比不一樣機架的兩臺機器的帶寬大。

經過一個機架感知的過程,NameNode能夠肯定每個Datanode所屬的機架id,一個簡單的策略是將副本放在不一樣的機架,能夠有效防止一個機架失效時數據的丟失,而且容許讀數據的時候充分利用各個機架的帶寬,這種策略設置能夠將副本均勻分佈在集羣中,有利於當組件失效的狀況下的負載均衡,可是 ,由於這種策略的一個寫操做須要傳輸數據塊到多個機架這樣增長了寫的代價。

多數狀況下副本系數時3,HDFS的存放策略時將一個副本存放在本地的機架上,一個副本放在同一機架的另一個節點上 ,最後一個副本放在不一樣機架的節點上,這種策略減小了機架間的數據傳輸,提升了寫操做的效率。機架間的錯誤遠比節點的錯誤少,這種策略提減小了讀取數據時須要的網絡傳輸總帶寬。這種策略下,副本並非均勻分佈在同一個機架上。三分之一的副本在一個節點,三分之二的副本在一個機架上,其餘副本均勻分佈在剩下的機架中,這種策略在不損害數據可靠性和可讀性能的狀況下改進了寫的性能。

分配原理

  • 有了機架感知,NameNode就能夠畫出下圖所示的datanode網絡拓撲圖,

最底層是Hx是 datanode, 則H1的rackid=/D1/R1/H1,H1的parent是R1,R1的是D1,有了這些rackid信息就能夠計算出任意兩臺datanode之間的距離

distance(/D1/R1/H1,/D1/R1/H1)=0  相同的datanode
distance(/D1/R1/H1,/D1/R1/H2)=2  同一rack下的不一樣datanode
distance(/D1/R1/H1,/D1/R1/H4)=4  同一IDC下的不一樣datanode
distance(/D1/R1/H1,/D2/R3/H7)=6  不一樣IDC下的datanode

 

  • 寫文件時根據策略輸入 dn 節點列表,讀文件時按與client由近到遠距離返回 dn 列表

文件讀取

  1. HDFS Client 經過FileSystem對象的Open方法打開要讀取的文件。

  2. DistributeFileSystem負責向遠程的元數據(NameNode)發起RPC調用,獲得文件的數據信息。返回數據塊列表,對於每一個數據塊,NameNode返回該數據塊的DataNode地址。

  3. DistributeFileSystem返回一個 FSDataInputSteam對象給客戶端,客戶端調用FSdataInputSteam對象的read()方法開始讀取數據。

  4. 經過對數據流反覆調用read()方法,把數據從數據節點傳輸到客戶端。

  5. 當數據讀取完畢時,DFSInputSteam對象會關閉此數據節點的連接,鏈接此文件下一個數據塊的最近數據節點。

  6. 當客戶端讀取完數據時,調用FSDataInputSteam對象的close()關閉輸入流。

API

方法名 返回值 說明
read(ByteBuffer buf) int 讀取數據放到buf緩衝區,返回所讀取的字節數。
read(long pos,byte[] buf, int offset ,int len) int 輸入流的指定位置開始把數據讀取到緩衝區中,pos指定從 輸入文件讀取的位置,offset數據寫入緩衝區位置的(偏移量)len讀操做的最大的字節數。
readFully(long pos,byte[] buff[]) void 從指定位置,讀取全部數據到緩衝區
seek(long set) void 指向輸入流的第offset字節
relaseBuffer(ByteBuffer buff) void 刪除

代碼

package hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;


public class DataInputStream {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://192.168.1.101:9000"),conf,"hadoop");
        Path src = new Path("/input/test");
        FSDataInputStream dis = fs.open(src);
        String str = dis.readLine();
        while (str.length() > 0) {
            System.out.println(str);
            str = dis.readLine();
            if (str == null) break;
        }
        dis.close();
    }
}

 

文件寫入

  1. 客戶端調用DistributedFileSystem對象的create方法建立一個文件輸出流對象
  2. DistributedFileSystem向遠程的NameNode系欸但發起一次RPC調用,NameNode檢查該文件是否存在,若是存在將會覆蓋寫入,以及客戶端是否有權限新建文件。
  3. 客戶端調用的FSDataOutputStream對象的write()方法寫數據,首先數據先被寫入到緩衝區,在被切分爲一個個數據包。
  4. 每一個數據包發送到用NameNode節點分配的一組數據節點的一個節點上,在這組數據節點組成的管線上依次傳輸數據包。
  5. 管線上的數據接按節點順序反向發揮確認信息(ack)最終由管線中的第一個數據節點將整條管線確認信息發給客戶端。

代碼

package hdfs;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

import java.net.URI;

public class DataOutputStream {
    public static void main(String[] args) throws Exception {

        Configuration conf = new Configuration();
        //設置 hdfs 地址 conf  用戶名稱
        FileSystem fs = FileSystem.get(new URI("hdfs://192.168.1.101:9000"), conf, "hadoop");

        //文件路徑
        Path path = new Path("/input/write.txt");

        //字符
        byte[] buff = "hello world".getBytes();
        FSDataOutputStream dos = fs.create(path);
        dos.write(buff);
        dos.close();
        fs.close();

    }
}

 

數據容錯

數據節點

每一個DataNode節點按期向NameNode發送心跳信號,網絡割裂會致使DataNode和NameNode失去聯繫,NameNode經過心跳信號的缺失來檢測DataNode是否宕機。當DataNode宕機時再也不將新的I/O請求發給他們。DataNode的宕機會致使數據塊的副本低於指定值,NameNode不斷檢測這些須要複製的數據塊,一旦發現低於設定副本數就啓動複製操做。在某個DataNode節點失效,或者文件的副本系數增大時均可能須要從新複製。

名稱節點

名稱節點保存了全部的元數據信息,其中最核心的兩大數據時fsimage和edits.logs,若是這兩個文件損壞,那麼整個HDFS實例失效。Hadoop採用了兩種機制來確保名稱節點安全。

  1. 把名稱節點上的元數據同步到其餘的文件系統好比(遠程掛載的網絡文件系統NFS)
  2. 運行一個第二名稱節點SecondaryNameNode當名稱節點宕機後,可使用第二名稱節點元數據進行數據恢復,但會丟失一部分數據。

所以會把兩種方式結合起來一塊兒使用,當名稱節點發生宕機的時候,首先到遠程掛載的網絡文件系統中獲取備份的元數據信息,放到第二名稱節點上進行恢復並把第二名稱節點做爲名稱節點來使用。

數據出錯

某個DataNode獲取的數據塊多是損壞的,損壞多是由DataNode的存儲設備錯誤,網絡錯誤或者軟件bug形成的。HDFS使用校驗和判斷數據塊是否損壞。當客戶端建立一個新的HDFS會計算這個每一個數據塊的校驗和。並將校驗和做爲一個單獨的隱藏文件保存在同一個HDFS命名空間下。當客戶端獲取文件內容後,它會檢驗從DataNode獲取的數據和對應的校驗是否匹配,若是不匹配客戶端從其餘Datanode獲取該數據塊的副本。HDFS的每一個DataNode還保存了檢查校驗和日誌,客戶端的每一次檢驗都會記錄到日誌中。

相關文章
相關標籤/搜索