大資料與Hadoop系列之壓縮(一)
Hadoop壓縮簡介
Hadoop作為一個較通用的海量數椐處理平臺,在使用壓縮方式方面,主要考慮壓縮速度和壓縮檔案的可分割性.
所有的壓縮演算法都會考慮時間和空間的權衡,更快的壓縮和解壓縮速度通常會耗費更多的交間(壓縮比較低)例如:通過gzip命令壓縮資料時,使用者可以設定不同的選項來選擇速度優先或空間優先.選項-1表示優先考慮速度,選項-9表示空間最優,可以獲得最大的壓縮比。
需要注意的是:有些壓縮演算法的壓縮和解壓縮速度會有比較大的差別:gzip和zip是通用的壓縮工具,在時間/空間處理上相對平衡,gzip2壓縮比gzip和zip更有效,但速度較慢,而且bzip2的解壓縮速度快於它的壓縮速度。
當使用MapReduce處理壓縮檔案時.需要考慮壓編檔案的可分割性。考慮我們需要對保持在HDFS上的一個大小為1GB的文字檔案進行處理,當HDFS的資料塊大小為64MB的情況下,該檔案被儲存為16塊,對應的MapReduce作業將會將該檔案分為16個輸人分片,提供給16個獨立的Map任務進行處理,但如果該檔案是一個gzip格式的壓縮檔案(大小不)。這時,MapReduce作業不能夠將該檔案分為16個分片,因為不可能從gzip數椐流中的某個點開始,進行資料解壓,但是,如果該檔案是一個bzip2格式的壓縮檔案,那麼.
MapReduce作業可以通過bZiP2格式壓緬檔案中的塊,將輸入劃分為若干輸入分片,並從塊開始處開始解壓縮數椐。bzip2格式壓縮檔案中,塊與塊間提供了一個48位的同步標記,因此,bzip2支援資料分割。
圖列出了一些可以用於Hadoop的常見壓縮格式以及特性。
為了支摶多種壓縮解壓縮演算法,Hadoop引入了編碼/解碼器。
Hadoop壓縮框架
Hadoop通過編碼/解碼器為基礎的抽象工廠法,提供了一個可擴充套件的框架,支援多種壓縮方法,下面就來研究Hadoop壓縮框架的實現。
1.編碼/解編碼
CompressionCodec介面實現編碼/解編碼,使用的是抽象工廠的設計模式。CompressionCodec提供一系列的方法,用於建立特定壓縮演算法的相關設施。
CompressionCodec中方法很對稱,一個壓縮功能總能對應著一個解壓縮編碼功能。其中,與壓縮相關的方法包括。
createOutputStream
使用壓縮器Compressor,在底層輸出流out的基礎上建立對應的壓縮流
createCompressor
建立壓縮演算法對應的壓縮器
CompressionCodec中還提供了獲取對應副檔名的方法getDefaultExtension,如對org.apache.hadoop.io.cpmpress.BZip2Codec,改方法返回字串".bz2",注意字串的第一個字元,相關程式碼如下。
CompressionCodecFactory適Hadoop壓縮框架中的另一個類,它應用了工廠方法,使用者可以通過它提供的方法獲得CompressionCodec。
注意
抽象工廠方法和工廠方法這兩個設計模式有很大的區別,抽象工廠方法用於建立一系列相關或互相依賴的物件,如CompressionCodec可以獲得和某一個壓縮演算法相關的物件,包括壓縮流和壓縮流等?而工廠方法(嚴格來說,CompressionCodecFactory是引數化工廠方法),用於建立多種產品,如通過CompressionCodecFactory的getCodec()方法,可以刻建GzipCodec物件或BZip2Codec物件。
在前面的例項中已經使用過getCodec()方法,為某一個壓縮檔案尋找對應的CompressionCodec。為了分析該方法,需要了解CompressionCodec類中儲存副檔名和CompressionCodec對映關係的成員變董codecs。
codecs是一個有序對映表,即它本身是一個Map,同時它對Map的鍵排序,下面是codecs中儲存的一個可能的對映關係:
{
2zb.:org.apache.hadoop.io.congress.BZip2Codec,
etalfed.:org.apache.hadoop.io.congress.DeflateCodec,
yppans.:org.apache.hadoop.io.compress.SnappyCodec,
zg.:org.apache.hadoop.io.compress.GzipCodec
}
可以看到,Map中的鍵是排序的,getCodec()方法的輸入是Path物件,儲存者檔案路徑,如例項中的“README.txt.bz2”.
首先通過獲取Path物件對應的檔名並逆轉該字串得到“2zb.txt.EMDAER”,然後通過有序對映SortedMap的headMap()方法,查詢最接近上述逆轉字串的有序對映的部分檢視,如輸人“2zb.txt.EMDAER”的查詢結采subMap,只包含“2zb.”對應的那個鍵-值對,
如果輸入垃“zg.txt.EMDAER”,則subMap會包含成員變數codccs中儲存的所有鍵-值對,
然後,簡單地獲取subMap最後一個元素的鍵,如果該鍵是逆轉檔名的字首,那麼就找到了檔案對應的編碼/解碼器,否則返回空,實現程式碼如下:
壓縮器和解壓器
壓縮器(Compressor)和解壓器(Decompressor)是Hadoop壓縮框架中的一對重要概念。
Compressor可以插入壓縮輸出流的實現中,提供具體的壓縮功能:相反,Decompressor提供具體的解壓功能並插人CompressionlnputStream中。Compressor和Decompressor的這種設汁,最初是在Java的zlib壓縮程式庫中引人的,對應的實現分別是java.util.zip.Deflater和java.util.zip.Inflater。下面以Compressor為例介紹這對元件。
Compressor的用法相對複雜,請參考org.hadoopinternal.compress.CompressDemo的compressor()方法,Compressor通過sctlnput()方法接收數椐到內部緩衝區,自然可以多次呼叫setlnput()方法,但內部緩衝區總是會被寫滿,如何判斷壓縮器內部緩衝區是否已滿呢?課以通過needsInput()的返回值,如果垃false,表明緩衝區已經滿,這時必須通過compress()方法獲取壓縮後的資料,釋放緩衝區空間.
為了提高壓縮效串,並不是每次使用者呼叫sctlnput()方法,壓縮器就會立即工作,所以,為了通知壓縮器所有資料已經寫人,必須使用finish()方法,finish()呼叫結束後,壓縮器緩衝區中保持的已經壓縮的資料,可以繼續通過compress()方法獲得,至於要判斷壓縮器中是否還有未讀取的以縮資料,則擗要利用finished()方法來判斷。
注意
finished()和finish()的作用不同,finish()結東資料輸入的過程,而finished()返回false,表明壓縮器中還有表讀取的壓堆資料,可以繼續通過compress()方法讀取。
舉個栗子:
未完待續........