Hadoop I/O系統介紹

    看過不少Hadoop介紹或者是學習的帖子和文章,發現介紹Hadoop I/O系統的不多。不少文章都會介紹HDFS的架構和使用,還有MapReduce編程等等。尤爲是在介紹Hadoop的MapReduce編程以前,首先必須瞭解下Hadoop的I/O知識,要不一看到IntWritable、LongWritable、Text、NullWritable等概念就有點犯暈,看到和普通的Java程序相似的MapReduce程序就以爲很難。若是這時候你知道其實IntWritable就是其餘語言如Java、C++裏的int類型,LongWritable就是其餘語言裏的long,Text相似String,NullWritable就是Null,這樣你就會很輕易的明白Hadoop 的MapReduce 程序。就像在學習其餘編程語言以前必須先學習數據類型同樣,在學習Hadoop的MapReduce編程以前,最好先學習下Hadoop的I/O知識。這裏就簡要介紹Hadoop的I/O知識,就當拋磚引玉吧。


    1序列化和反序列化
     序列化(Serialization)就是結構化的對象轉化爲字節流,這樣能夠方便在網絡上傳輸和寫入磁盤進行永久存儲(緣由看完這部分後就明白了)。反序列化(deserialization)就是指將字節流轉回結構化對象的逆過程。
    序列化和反序列化在分佈式數據處理裏主要出如今進程間通行和永久存儲兩個應用領域。在Hadoop 系統中,系統中多個節點上的進程間通訊是經過遠程過程調用(romote procedure call,R PC)實現的,RPC協議將消息序列轉化爲二進制流後發送到遠程節點,遠程節點接着將二進制流反序列化爲消息,因此RPC對於序列化有如下要求(也就是進程間通訊對於序列化的要求):
    (1)緊湊,緊湊的格式能夠提升傳輸效率,充分利用網絡帶寬,要知道網絡帶寬是數據中心的一種很是重要的資源。
    (2)快速,進程間通訊是分佈是系統的重要內容,因此必須減小序列化和反序列化的開銷,這樣能夠提升整個分佈式系統的性能。
    (3)可擴展,通訊協議爲了知足一些新的需求,好比在方法調用的過程當中增長新的參數,或者新的服務器系統要可以接受老客戶端的舊的格式的消息,這樣就須要直接引進新的協議,序列化必須知足可擴展的要求。
    (4)互操做,能夠支持不一樣語言寫的客戶端(好比C++、java、Python等等)與服務器交互。
     前面說了序列化的目的是能夠方便在網絡上傳輸和寫入磁盤進行永久存儲,前面講了進程間通訊對於序列化的要求,下面來講一說數據永久存儲對於序列化的要求。前面說的4個序列化的要求也是數據永久存儲所要求的,存貯格式緊湊能夠高效的利用存儲空間,快速能夠減小讀寫數據的額外開銷,可擴張這樣就能夠方便的讀取老格式的數據,互操做就能夠知足不一樣的編程序言來讀寫永久存貯的數據。


    2 Hadoop的序列化格式——Writabale
    前面介紹了序列化對於分佈式系統是相當重要的,Hadoop 定義了本身的序列化格式Writable,它是經過Java語言實現的,格式緊湊速度快。Writable是Hadoop的核心,不少MapReduce程序都會爲鍵和值使用它。
    2.1Writabale接口
    Writable接口定義了兩個方法,一個將其狀態寫到DataOutput二進制流(往二進制流裏面寫數據),一個從DataInput二進制流讀取其狀態(從二進制流裏讀取數據)。
    2.2Writable類

    Hadoop自帶的org.apache.hadoop.io包含有普遍的Writable類可供選擇。下面給出Writable類的層次結構。 java

        

    下面介紹幾個經常使用的Writable類:
    (1)Text類:
        Text類是針對UTF-8序列(UTF-8是UNICODE的一種變長字節字符編碼,又稱萬國碼)的Writable類,通常認爲他等價與java.lang.String的Writable類。可是他和String仍是有一些差別的。Text的索引是按編碼後字節序列中的位置來實現的,String是按其所包含的char編碼單元來索引的。看下面的例子:
            String s=String("\u0041\u00df\uu6671\ud801\uDc00");
            Text t=Text("\u0041\u00df\uu6671\ud801\uDc00");
            s.indexof("\u0041")==0            t.find("\u0041")==0
            s.indexof("\u00df")==1             t.find("\u00df")==1
            s.indexof("\u6671")==2            t.find("\u6671")==3
            s.indexof("\ud801\uDc00")==3 t.find(\ud801\uDc00")==6
            s.length()==5    s.getBytes("UTF-8").length()==10
            t.getLength()==10(1+2+3+4)
        經過字節偏移量來進行位置索引,實現對Text類的Unicode字符迭代是很是複雜的,由於不能簡單的經過增長位置的索引值來實現。因此必先將Text對象轉化爲java.nio.BytesBuffer對象,而後利用緩衝區對Text對象反覆調用bytesToCodePoint()靜態方法,該方法能獲取下一代碼的位置。
        因爲Text類不像java.lang.String類那樣有豐富的字符串操做API,因此在一些狀況下爲了方便處理,須要將Text類轉化爲String類,這一過程經過toString來實現。
    (2)ByteWritable類,二進制數據數組的封裝,它的序列化格式爲一個用於指定後面數據字節數的整數域(4字節),後跟字節自己。
    (3)NullWritabe,是Writable的一個特殊類型,它的序列化長度爲0,相似於null。
    (4)ObjectWritable類,是對java基本類型(String,enum,Writable,null或這些類型組成的數組)的一個通用封裝。
    (5)Writable集合類,共有4個集合類,其中ArrayWritable是對Writable的數組的實現,TwoDArrayWritable是對Writable的二維數組的實現,MapWritable是對Map的實現,SortedMapWritable是對SortedMap的實現。
    (6)定製的Writable類,咱們能夠根據本身的需求構造本身的Writable類,能夠根據須要控制二進制表示和排序順序,因爲Writable是MapReduce數據路徑的核心,因此調整二進制表示能對性能殘生顯著效果。


    3 Hadoop的序列化框架——Avro
    Avro(讀音相似於[ævrə])是Hadoop的一個子項目,由Hadoop的創始人Doug Cutting(也是Lucene,Nutch等項目的創始人,膜拜)牽頭開發,當前最新版本1.3.3。Avro是一個數據序列化系統,設計用於支持大批量數據交換的應用。它的主要特色有:支持二進制序列化方式,能夠便捷,快速地處理大量數據;動態語言友好,Avro提供的機制使動態語言能夠方便地處理Avro數據。 
     當前市場上有不少相似的序列化系統,如Google的Protocol Buffers, Facebook的Thrift。這些系統反響良好,徹底能夠知足普通應用的需求。針對重複開發的疑惑,Doug Cutting撰文解釋道:Hadoop現存的RPC系統遇到一些問題,如性能瓶頸(當前採用IPC系統,它使用Java自帶的DataOutputStream和DataInputStream);須要服務器端和客戶端必須運行相同版本的Hadoop;只能使用Java開發等。但現存的這些序列化系統自身也有毛病,以Protocol Buffers爲例,它須要用戶先定義數據結構,而後根據這個數據結構生成代碼,再組裝數據。若是須要操做多個數據源的數據集,那麼須要定義多套數據結構並重復執行屢次上面的流程,這樣就不能對任意數據集作統一處理。其次,對於Hadoop中Hive和Pig這樣的腳本系統來講,使用代碼生成是不合理的。而且Protocol Buffers在序列化時考慮到數據定義與數據可能不徹底匹配,在數據中添加註解,這會讓數據變得龐大並拖慢處理速度。其它序列化系統有如Protocol Buffers相似的問題。因此爲了Hadoop的前途考慮,Doug Cutting主導開發一套全新的序列化系統,這就是Avro,於09年加入Hadoop項目族中。
      Avro是Hadoop中的一個重要的項目,不是三言兩語能說清楚的,這片文章是專門介紹Avro的,感受寫的不錯,我前面寫的這段來自於這篇文章,地址:[http://langyu.iteye.com/blog/708568]


    4 SequenceFile和MapFile
    Hadoop的HDFS和MapReduce子框架主要是針對大數據文件來設計的,在小文件的處理上不但效率低下,並且十分消耗內存資源(每個小文件佔用一個Block,每個block的元數據都存儲在namenode的內存裏)。解決辦法一般是選擇一個容器,將這些小文件組織起來統一存儲。HDFS提供了兩種類型的容器,分別是SequenceFile和MapFile。
    這一篇博文是專門介紹SequenceFile和MapFile的,寫的不錯,想詳細理解的能夠查看,文章地址:http://blog.csdn.net/javaman_chen/article/details/7241087。


    關於Hadoop I/O還有數據的完整性和數據壓縮的知識,因爲篇幅緣由,這裏再也不一一介紹。
相關文章
相關標籤/搜索