hadoop数据压缩
简介数据压缩
在hadoop中,压缩技术可以有效的减少底层存储系统HDFS的读写的字节数。还能提高网络带宽和磁盘空间的效率。在Hadoop下,尤其是当数据规模很大和网络数据传输要花费大量的时间,shuffle和merge过程也面临着巨大的io压力。
- 压缩的策略和原则:
- 压缩是一种提高hadoop运行效率的优化策略。
- 通过对mapper、reducer运行过程的数据进行压缩,减少io、提高mr程序的运行速度。
- 采用压缩虽然降低了io,但却增加了cpu的负担
- 压缩的基本原则:
- 运算密集型job,少用压缩
- io密集型job,多用压缩
mr支持的压缩编码
压缩格式 | hadoop自带? | 算法 | 文件扩展名 | 是否可切分 | 换成压缩格式后,原来的程序是否需要修改 |
---|---|---|---|---|---|
DEFLATE | 是,直接使用 | DEFLATE | .deflate | 否 | 和文本处理一样,不需要修改 |
Gzip | 是,直接使用 | DEFLATE | .gz | 否 | 和文本处理一样,不需要修改 |
bzip2 | 是,直接使用 | bzip2 | .bz2 | 是 | 和文本处理一样,不需要修改 |
LZO | 否,需要安装 | LZO | .lzo | 是 | 需要建索引,还需要指定输入格式 |
Snappy | 否,需要安装 | Snappy | .snappy | 否 | 和文本处理一样,不需要修改 |
为了支持多种压缩解压算法,hadoop引入了编码解码器:
压缩格式 | 对应的编码/解码器 |
---|---|
DEFLATE | org.apache.hadoop.io.compress.DefaultCodec |
gzip | org.apache.hadoop.io.compress.GzipCodec |
bzip2 | org.apache.hadoop.io.compress.BZip2Codec |
LZO | com.hadoop.compression.lzo.LzopCodec |
Snappy | org.apache.hadoop.io.compress.SnappyCodec |
压缩算法的性能比较
压缩算法 | 原始文件大小 | 压缩文件大小 | 压缩速度 | 解压速度 |
---|---|---|---|---|
gzip | 8.3GB | 1.8GB | 17.5MB/s | 58MB/s |
bzip2 | 8.3GB | 1.1GB | 2.4MB/s | 9.5MB/s |
LZO | 8.3GB | 2.9GB | 49.3MB/s | 74.6MB/s |
snappy:
http://google.github.io/snappy/
On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250 MB/sec or more and decompresses at about 500 MB/sec or more.
压缩方式的选择
-
Gzip压缩
- 优点:
- 压缩率高、压缩解压速度比较快;
- hadoop本身支持,在应用中处理Gzip格式的文本与直接处理文本一样;
- 大部分linux都自带Gzip命令,只用方便;
- 缺点
- 不支持切片
- 应用场景:
- 当每个文件压缩后都在一个块大小以内时,可以考虑用gzip。如每个一段时间生成的日志压缩成一个gzip文件
- 优点:
-
Bzip2
- 优点
- 支持切片
- 有很高的压缩率
- hadoop本身支持
- 在linux系统下自带Bzip2命令,使用方便
- 缺点:
- 压缩解压速度慢
- 应用场景
- 适合对速度要求不高但是需要较高的压缩率的时候,可以作为mr作业的输出格式;或者时输出之后的数据很大需要减少磁盘空间且用得不多的情况;对单个很大文件向压缩减少空间同时又需要支持切片且兼容之前的应用程序的情况
- 优点
-
lzo
- 优点
- 压缩解压速度快,压缩率合理
- 支持切片
- 缺点
- 压缩率比gzip低一些
- hadoop本身不支持,需要安装
- 在应用中需要对lzo文件做一些处理
- 应用场景
- 一个很大的文本文件,压缩后还大于200m以上可以考虑,且一个文件越大。lzo优点越明显。
- 优点
-
snappy压缩
- 优点
- 高速压缩
- 合理的压缩率
- 缺点
- 不支持切片
- 压缩率比gzip低
- hadoop本身不支持
- 应用场景
- 当mr作业的map输出数据比较大的时候,作为map到reduce的中间数据压缩格式;
- 或者作为一个mr作业到另一个mr作业间的数据传输
- 优点
压缩位置的选择
压缩可以发生在mr作业的任意阶段启用
压缩参数配置
参数 | 默认值 | 阶段 | 建议 |
---|---|---|---|
io.compression.codecs (在core-site.xml中配置) | org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec | 输入压缩 | Hadoop使用文件扩展名判断是否支持某种编解码器 |
mapreduce.map.output.compress(在mapred-site.xml中配置) | false | mapper输出 | 这个参数设为true启用压缩 |
mapreduce.map.output.compress.codec(在mapred-site.xml中配置) | org.apache.hadoop.io.compress.DefaultCodec | mapper输出 | 使用LZO或Snappy编解码器在此阶段压缩数据 |
mapreduce.output.fileoutputformat.compress(在mapred-site.xml中配置) | false | reducer输出 | 这个参数设为true启用压缩 |
mapreduce.output.fileoutputformat.compress.codec(在mapred-site.xml中配置) | org.apache.hadoop.io.compress. DefaultCodec | reducer输出 | 使用标准工具或者编解码器,如gzip和bzip2 |
mapreduce.output.fileoutputformat.compress.type(在mapred-site.xml中配置) | RECORD | reducer输出 | SequenceFile输出使用的压缩类型:NONE和BLOCK |
压缩案例实操
-
压缩解压测试
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.compress.BZip2Codec; import org.apache.hadoop.io.compress.CompressionCodec; import org.apache.hadoop.io.compress.CompressionInputStream; import org.apache.hadoop.io.compress.CompressionOutputStream; import org.apache.hadoop.util.ReflectionUtils; import org.junit.Test; import java.io.*; import java.net.URI; import java.net.URISyntaxException; /** * 对压缩的测试类 */ public class CompressTest { /** * 压缩测试 */ @Test public void testCompress() throws URISyntaxException, IOException, ClassNotFoundException { //打开输入流 FileInputStream fis = new FileInputStream( new File(new URI("file:///e:/work/test/input/w.txt"))); //反射创建压缩类对象 CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(BZip2Codec.class,new Configuration()); //创建输出流 FileOutputStream fos = new FileOutputStream( "e:/work/test/w.txt" + codec.getDefaultExtension()); CompressionOutputStream compressStream = codec.createOutputStream(fos); //流的对拷 IOUtils.copyBytes(fis,compressStream,new Configuration(),true); } /** * 测试解压 */ @Test public void testDecompress() throws URISyntaxException, IOException { //打开输入流 FileInputStream fis = new FileInputStream( new File(new URI("file:///e:/work/test/w.txt.bz2"))); //获取压缩类实例 CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(BZip2Codec.class,new Configuration()); CompressionInputStream compressInputStream = codec.createInputStream(fis); //输出流 FileOutputStream fos = new FileOutputStream("e:/work/test/wuzou.txt"); //对拷 IOUtils.copyBytes(compressInputStream,fos,new Configuration(),true); } }
-
实际使用
在mr程序中实际使用压缩只要在driver中修改几个参数即可
mapper输出压缩:
// 开启map端输出压缩
configuration.setBoolean("mapreduce.map.output.compress", true);
// 设置map端输出压缩方式
configuration.setClass("mapreduce.map.output.compress.codec",BZip2Codec.class, CompressionCodec.class);
reduce输出压缩:
// 设置reduce端输出压缩开启
FileOutputFormat.setCompressOutput(job, true);
// 设置压缩的方式
FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class);