hadoop中使用lzo的壓縮

破棉襖發表於2014-07-16

在hadoop中使用lzo的壓縮演算法可以減小的大小和資料的磁碟讀寫時間,不僅如此,lzo是基於block分塊的,這樣他就允許資料被分解成chunk,並行的被hadoop處理。這樣的特點,就可以讓lzo在hadoop上成為一種非常好用的壓縮格式。

lzo本身不是splitable的,所以當資料為text格式時,用lzo壓縮出來的資料當做job的輸入是一個檔案作為一個map。但是sequencefile本身是分塊的,所以sequencefile格式的檔案,再配上lzo的壓縮格式,就可實現lzo檔案方式的splitable。

由於壓縮的資料通常只有原始資料的1/4,在HDFS中儲存壓縮資料,可以使叢集能儲存更多的資料,延長叢集的使用壽命。不僅如此,由於mapreduce作業通常瓶頸都在IO上,儲存壓縮資料就意味這更少的IO操作,job執行更加的高效。但是,在hadoop上使用壓縮也有兩個比較麻煩的地方:第一,有些壓縮格式不能被分塊,並行的處理,比如gzip。第二,另外的一些壓縮格式雖然支援分塊處理,但是解壓的過程非常的緩慢,使job的瓶頸轉移到了cpu上,例如bzip2。比如我們有一個1.1GB的gzip檔案,該 被分成128MB/chunk儲存在hdfs上,那麼它就會被分成9塊。為了能夠在mapreduce中並行的處理各個chunk,那麼各個mapper之間就有了依賴。而第二個mapper就會在檔案的某個隨機的byte出進行處理。那麼gzip解壓時要用到的上下文字典就會為空,這就意味這gzip的壓縮檔案無法在hadoop上進行正確的並行處理。也就因此在hadoop上大的gzip壓縮檔案只能被一個mapper來單個的處理,這樣就很不高效,跟不用mapreduce沒有什麼區別了。而另一種bzip2壓縮格式,雖然bzip2的壓縮非常的快,並且甚至可以被分塊,但是其解壓過程非常非常的緩慢,並且不能被用streaming來讀取,這樣也無法在hadoop中高效的使用這種壓縮。即使使用,由於其解壓的低效,也會使得job的瓶頸轉移到cpu上去。

如果能夠擁有一種壓縮演算法,即能夠被分塊,並行的處理,速度也非常的快,那就非常的理想。這種方式就是lzo。lzo的壓縮檔案是由許多的小的blocks組成(約256K),使的hadoop的job可以根據block的劃分來splitjob。不僅如此,lzo在設計時就考慮到了效率問題,它的解壓速度是gzip的兩倍,這就讓它能夠節省很多的磁碟讀寫,它的壓縮比的不如gzip,大約壓縮出來的檔案比gzip壓縮的大一半,但是這樣仍然比沒有經過壓縮的檔案要節省20%-50%的儲存,這樣就可以在效率上大大的提高job執行的速度。以下是一組壓縮對比資料,使用一個8.0GB的未經過壓縮的資料來進行對比:

壓縮格式 檔案 大小(GB) 壓縮時間 解壓時間
None some_logs 8.0 - -
Gzip some_logs.gz 1.3 241 72
LZO some_logs.lzo 2.0 55 35

可以看出,lzo壓縮檔案會比gzip壓縮檔案稍微大一些,但是仍然比原始檔案要小很多倍,並且lzo檔案壓縮的速度幾乎相當於gzip的5倍,而解壓的速度相當於gzip的兩倍。lzo檔案可以根據blockboundaries來進行分塊,比如一個1.1G的lzo壓縮檔案,那麼處理第二個128MBblock的mapper就必須能夠確認下一個block的boundary,以便進行解壓操作。lzo並沒有寫什麼資料頭來做到這一點,而是實現了一個lzoindex檔案,將這個檔案(foo.lzo.index)寫在每個foo.lzo檔案中。這個index檔案只是簡單的包含了每個block在資料中的offset,這樣由於offset已知的緣故,對資料的讀寫就變得非常的快。通常能達到90-100MB/秒,也就是10-12秒就能讀完一個GB的檔案。一旦該index檔案被建立,任何基於lzo的壓縮檔案就能透過load該index檔案而進行相應的分塊,並且一個block接一個block的被讀取。也因此,各個mapper都能夠得到正確的block,這就是說,可以只需要進行一個LzopInputStream的封裝,就可以在hadoop的mapreduce中並行高效的使用lzo。如果現在有一個job的InputFormat是TextInputFormat,那麼就可以用lzop來壓縮檔案,確保它正確的建立了index,將TextInputFormat換成LzoTextInputFormat,然後job就能像以前一樣正確的執行,並且更加的快。有時候,一個大的檔案被lzo壓縮過之後,甚至都不用分塊就能被單個mapper高效的處理了。

在hadoop叢集中安裝lzo

要在hadoop中搭建lzo使用環境非常簡單:

  1. 安裝lzop native libraries
    例如:sudo yum install lzop lzo2
  2. 從如下地址下載 hadooplzo支援到原始碼:
  3. 編譯從以上鍊接checkout下來到程式碼,通常為:ant compile-native tar
  4. 將編譯出來到hadoop-lzo-*.jar部署到hadoop叢集到各個slave到某個有效目錄下,如$HADOOOP_HOME/lib
  5. 將以上編譯所得到hadoop-lzo native libbinary部署到叢集到某個有效目錄下,如$HADOOP_HOME/lib/native/Linux-amd64-64。
  6. 將如下配置到 core-site.xml 中:
    
    io.compression.codecs
    org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.BZip2Codec,com.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodec
    
    
    io.compression.codec.lzo.class
    com.hadoop.compression.lzo.LzoCodec
    
    
  7. 將如下配置到mapred-site.xml中:
    
    mapred.child.env
    JAVA_LIBRARY_PATH=/path/to/your/native/hadoop-lzo/libs
    
    
  8. 如果想要mapreduce再寫中間結果時也使用壓縮,可以將如下配置也寫入到mapred-site.xml中。
    
    mapred.map.output.compression.codec
    com.hadoop.compression.lzo.LzoCodec
    
    

如果以上所有操作都成功,那麼現在就可以嘗試使用lzo了。比如打包一個lzo都壓縮檔案,如lzo_log檔案,上傳到hdfs中,然後用以下進行測試:
hadoop jar /path/to/hadoop-lzo.jarcom.hadoop.compression.lzo.LzoIndexerhdfs://namenode:9000/lzo_logs

如果要寫一個job來使用lzo,可以找一個job,例如wordcount,將當中到TextInputFormat修改為LzoTextInputForma,其他都不用修改,job就能從hdfs上讀入lzo壓縮檔案,進行分散式都分塊並行處理。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29754888/viewspace-1220347/,如需轉載,請註明出處,否則將追究法律責任。

相關文章