hadoop中支持的壓縮方式有多種,比如Gzip,bzip2,zlib等,其中Gzip是hadoop中內置就支持的一種壓縮方式,這種壓縮方式在平時linux的開發人員和管理員中使用的比較廣泛,壓縮比也比較高,壓縮速度也還不錯,所以很多人都喜歡第一趨向於使用這種壓縮格式進行文件的壓縮。
在hadoop中,要在mapreduce 的job中使用gzip壓縮是比較容易的,不記得是從哪個版本開始,hadoop就內置了使用gzip壓縮格式讀取輸入文件,寫中間結果和輸出結果的支持。
1.從壓縮的輸入文件時直接讀入
由於hadoop在讀取輸入文件時,會很智能的根據輸入文件的后綴名來進行判斷是否采用壓縮格式進行讀入,所以當讀到輸入文件是***.gz時,就會猜測該文件是一個用gzip壓縮過的文件,於是就會嘗試使用gzip的讀取方式來讀取.
public
CompressionCodecFactory(Configuration conf) { codecs
=
new
TreeMap
<
String, CompressionCodec
>
(); List
<
Class
<?
extends
CompressionCodec
>>
codecClasses
=
getCodecClasses(conf);
//
conf.get("io.compression.codecs");從這個配置里面取得配置的解碼器
if
(codecClasses
==
null
) { addCodec(
new
GzipCodec());
//
如果core-site.xml里面沒有配置的話 就是有默認的這2個
addCodec(
new
DefaultCodec()); }
else
{ Iterator
<
Class
<?
extends
CompressionCodec
>>
itr
=
codecClasses.iterator();
while
(itr.hasNext()) { CompressionCodec codec
=
ReflectionUtils.newInstance(itr.next(), conf); addCodec(codec); } } }
如果使用其他的壓縮方式可以這樣來配置在core-site.xml中
<
property
>
<
name
>
io.compression.codecs
</
name
>
<
value
>
org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,com.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodec
</
value
>
</
property
>
或者在代碼中
conf.set(
"
io.compression.codecs
"
,
"
org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.GzipCodec,com.hadoop.compression.lzo.LzopCodec
"
);
在默認的inputformat或者outputformat里面,都自帶編解碼的檢測代碼,如果自己實現format的話,可能需要自己添加如下代碼
實現inputformat
CompressionCodecFactory compressionCodecs
=
new
CompressionCodecFactory(job);
final
CompressionCodec codec
=
compressionCodecs.getCodec(file); CompressionInputStreamin
=
codec.createInputStream(fileIn); ....
Class
<?
extends
CompressionCodec
>
codecClass
=
getOutputCompressorClass(job, GzipCodec.
class
); CompressionCodec codec
=
(CompressionCodec)ReflectionUtils.newInstance(codecClass, job); Path file
=
FileOutputFormat.getTaskOutputPath(job,name
+
codec.getDefaultExtension()); FileSystem fs
=
file.getFileSystem(job); FSDataOutputStream fileOut
=
fs.create(file, progress); CompressionOutputStreamout
=
codec.createOutputStream(fileOut)) ....
2.將mapreduce job所產生的中間結果進行壓縮
由於mapreduce算法本身的特征,必然會在job的運行過程中產生一定的中間結果文件,當數據量 很大的時候,這些中間結果也非常的客觀,一定程度上,對job的效率會有一定的影響。由於通常計算任務的瓶頸都在磁盤的讀寫IO上,因此如果能夠減少因中 間文件而產生的disk IO,則對作業的效率肯定有益無害。因此如果希望將mapreduce作業的中間結果進行壓縮,在hadoop的conf(可以通過修改hadoop- site.xml的配置選項,可以在程序中用JobConf的類接口設置,或者在提交作業時用-D選項來設置該選項)中配置一個選項:
<
property
>
<
name
>
mapred.compress.map.output
</
name
>
<
value
>
true
</
value
>
</
property
>
conf.setCompressMapOutput(
true
); conf.setMapOutputCompressorClass(GzipCodec.
class
);
這樣,作業就會將產生的中間結果寫入slave local的時候,對結果進行壓縮,reduce讀取時也能夠根據gz的后綴知道該中間結果是壓縮文件,於是采用相應的讀取格式來讀取。
3.將最終的計算輸出的結果進行壓縮
有的時候,我們需要對作業的運行結果進行歷史保存,但是如果每天積累的計算結果非常大,又想要保存盡量多的歷史結果一邊將來的結算,那么日積月累下,就會占據非常非常大的HDFS的存儲空間, 並且由於是歷史數據,使用的頻率也不高,這就會造成很大的存儲空間的浪費,因此,將計算的結果進行壓縮,也是一種非常好的節省空間的方法。要在 hadoop job中做到這一點也很容易,只需要告訴hadoop,“我想要多job的輸出結果進行壓縮,並保存到HDFS上去”,就行了。具體的操作就是:在 conf中設置配置選項:
<
property
>
<
name
>
mapred.output.compress
</
name
>
<
value
>
true
</
value
>
</
property
>
conf.setBoolean(
"
mapred.output.compress
"
,
true
); conf.setClass(
"
mapred.output.compression.codec
"
, GzipCodec.
class
,CompressionCodec.
class
);
4.是使用hadoop-0.19.1對一個任務進行三種方式的壓縮的對比:
-
讀取非壓縮文件,中間結果不壓縮,輸出結果也不壓縮
- 讀取壓縮文件,中間結果不壓縮,輸出結果不壓縮
- 讀取非壓縮文件,中間結果壓縮,輸出結果不壓縮
- 讀取非壓縮文件,中間結果不壓縮,輸出結果壓縮
因此我們可以看到,在hadoop中使用gzip壓縮來進行讀取,中間結果,數據結果的保存都是非常的容易,因為hadoop native本身就提供了我們相應的類來解析和壓縮數據。不過這里要特別提到的是:gzip壓縮格式在hadoop中的支持有一定的局限性: 由於gzip壓縮算法本身的原因,我們無法對gzip壓縮文件進行分塊,也就是說,在hadoop中,如果想要用hadoop 的mapreduce來處理數據,沒一個mapper就必須對應一個gz文件,不能多個mapper對一個gzip文件的多個chunk進行並行的處理, 因此如果要在hadoop mapreduce任務中使用gzip,在數據處理之前就需要對數據進行認為的切分,讓一個mapper來處理一塊數據。這樣其實有一點有違 mapreduce的本質。
