Hadoop数据压缩

一、概述

压缩技术可以有效减少底层存储(HDFS)读写字节数。压缩提高了网络带宽与磁盘空间效率。在运行MR时,IO、网络数据传输、Shuffle和Merge要花费大量时间,尤其是数据规模很大和负载密集的情况下,因此使用数据压缩显得非常重要。
磁盘IO和网络带宽是Hadoop的宝贵资源,数据压缩对于节省资源、最小化磁盘IO和网络传输非常有帮助,可以在任意阶段启用压缩采用压缩技术减少了磁盘IO,但同时也增加了CPU的运算负担,压缩技术运用得当可以提高性能,但运用不当也可能降低性能。
基本原则:

  1. 运算密集型job,少用压缩
  2. IO密集型的job,多用压缩

二、压缩方式

2.1 Gzip压缩

  • 优点:压缩率比较高,压缩速度比较快.Hadoop本身支持,在应用中处理Gzip格式文件和直接处理文本一样,大部分Linux自带Gzip命令。
  • 缺点:不支持Split
  • 应用场景:当每个文件压缩之后在一个块大小内,都可以考虑使用Gzip压缩格式。

2.2 Bzip2压缩

  • 优点: 支持Split,具有很高的压缩率,比Gzip压缩了高,Hadoop本身自带,使用方便。
  • 缺点:压缩/解压速度慢
  • 应用场景:适合对速度要求不高,但需要较高的压缩率的时候,或者输出之后的数据比较大。处理之后的数据需要压缩存档减少磁盘空间,并且以后的数据用的较少的情况,或者对单个很大的文本文件想压缩减少存储空间,同时又需要支持Split,而且兼容之前的应用程序。

2.3 Lzo压缩

  • 优点:压缩/解压速度也比较快,合理的压缩率。支持Split,是Hadoop中最流行的压缩格式,可以在Linux中安装Lzop命令,使用方便。
  • 缺点:压缩率比Gzip要低一点,Hadoop本身不支持,需要安装。在应用中对Lzo格式的文件需要做些特殊的处理(为了支持Split需要建索引,还需要指定InputFormat为Lzo格式)

2.4 Snappy压缩

  • 优点:高速压缩速度和和合理的压缩率
  • 缺点:不支持Split;压缩率比Gzip高,Hadoop本身不知福,需要安装。
  • 应用场景:当MapReduce作业的Map输出数据比较大的时候,作为Map到Reduce的中间数据的压缩格式。或者作为一个MapReduce的作业输出和另外一个MapReduce的输入

2.5 压缩总结对比

压缩格式1hadoop自带算法文件扩展名可切分?换成压缩格式后,原来的程序是否需要修改
DEFAULTDEFAULT.deflate和文本处理一样,不需要修改
GzipDEFAULT.gz和文本处理一样,不需要修改
bzip2bzip2.bz2和文本处理一样,不需要修改
LZOLZO.lzo需要建索引,还需要指定输入格式
SnappySnappy.snappy和文本处理一样,不需要修改
压缩格式对应编码/解码器
DEFLATEorg.apache.hadoop.io.compress.DefaultCodec
gziporg.apache.hadoop.io.compress.GzipCodec
bzip2org.apache.hadoop.io.compress.BZip2Codec
LZOcom.hadoop.compression.lzo.LzopCodec
Snappyorg.apache.hadoop.io.compress.SnappyCodec

压缩速度与效率对比:
在这里插入图片描述

三、压缩位置选择

  • Map强压缩

在有大量数据并计划重复处理的情况下,应该考虑对输入数据记下来压缩,压缩时无需指定使用的编码方式,Hadoop自动检查文件扩展名,如果扩展名能够匹配,就会用恰当的解码方式进行解压,否则Hadoop就不会使用任何编解码器。

  • Map之后,Reduce之前

当Map任务输出的中间数据很大时,应该考虑使用压缩。这能够显著改变内部数据的Shuffle过程,Shuffle过程在Hadoop中是资源消耗最多的环节,如果发现数据量大造成网络传输缓慢,应该考虑使用压缩技术。可用于压缩Mapper输出的快速编解码器LZO或者Snappy。
注:LZO是供Hadoop压缩数据通用压缩编解码器。设计目的是达到与硬盘读取速度相当的压缩速度,因此速度是优先考虑的因素,而不是压缩率。

  • Reduce之后

在此阶段启用压缩技术能够减少要存储的数据量,因此降低所需的磁盘空间。当MapReduce作业形成作业两条时,因为第二个作业的输入也已压缩,所以用压缩同样有效。

压缩的参数配置:

文件位置参数默认值阶段备注
core-site.xmlio.compression.codecsorg.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.BZip2Codec输入压缩Hadoop使用文件扩展名判断是否支持某种编解码器
mapred-site.xmlmapreduce.map.output.compressfalsemapper输出true启用mapper压缩
mapred-site.xmlmapreduce.map.output.compress.codeorg.apache.hadoop.io.compress.DefaultCodecmapper输出企业使用LZO或Snappy编解码器在此阶段压缩数据
mapred-site.xmlmapreduce.output.fileoutputformat.compressfalsereducer输出true开启reduce压缩
mapred-site.xmlmapreduce.output.fileoutputformat.compress.codecorg.apache.hadoop.io.compress. DefaultCodecreducer输出使用标准工具或者解码器,如gzip或gzip2
mapred-site.xmlmapreduce.output.fileoutputformat.compress.typeRECORDreducer输出SequenceFile输出使用的压缩类型:NONE和BLOCK

四、文件压缩

CompressionCodec有两个方法可以用于轻松地压缩或解压缩数据。

  • 要想对正在被写入一个输出流的数据进行压缩,我们可以使用createOutputStream(OutputStreamout)方法创建一个CompressionOutputStream,将其以压缩格式写入底层的流。
  • 相反,要想对从输入流读取而来的数据进行解压缩,则调用createInputStream(InputStreamin)函数,从而获得一个CompressionInputStream,从而从底层的流读取未压缩的数据。
public class TestCompress {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        String sourcePath = "e:/input/web.log";
        String destPath = "e:/input/web";

//        String clazz = "org.apache.hadoop.io.compress.DefaultCodec";
//        String clazz = "org.apache.hadoop.io.compress.GzipCodec";
//        String clazz = "org.apache.hadoop.io.compress.BZip2Codec";

//        compress(sourcePath, destPath, clazz);

        String fileName = "e:/input/web.bz2";
        deCompress(fileName);

    }

    // 解压
    private static void deCompress(String fileName) throws IOException {

        // 1. 校验是否能解压缩
        CompressionCodecFactory codecFactory = new CompressionCodecFactory(new Configuration());
        CompressionCodec codec = codecFactory.getCodec(new Path(fileName));

        if (codec == null){
            System.out.println("cannot find codes for file "+ fileName);
            return;
        }

        // 2.获取输入流
        FileInputStream fis = new FileInputStream(new File(fileName));
        CompressionInputStream cis = codec.createInputStream(fis);

        // 3.获取输出流
        FileOutputStream fos = new FileOutputStream(new File(fileName + ".decoded"));

        // 4.流的对拷
        IOUtils.copyBytes(cis, fos, 1024*1024*5, false);

        fos.close();
        cis.close();
        fis.close();

    }

    // 压缩
    private static void compress(String sourcePath, String destPath, String clazz) throws IOException,
            ClassNotFoundException {

        // 1.获取输入流
        FileInputStream fis = new FileInputStream(new File(sourcePath));

        // 利用反射获取类信息
        Class<?> codeClass = Class.forName(clazz);
        CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codeClass,
                new Configuration());

        // 2.获取输出流
        FileOutputStream fos = new FileOutputStream(new File(destPath + codec.getDefaultExtension()));
        // 转换成可以进行压缩的流
        CompressionOutputStream cos = codec.createOutputStream(fos);

        IOUtils.copyBytes(fis, cos, 1024*1024*5, false);

        cos.close();
        fos.close();
        fis.close();
    }

}

Map输出采用压缩:

// 开启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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

b u g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值