十六、Hadoop中的数据压缩

       本文主要讲述Hadoop中的数据压缩,这也是MapReduce中的最后一篇文章了,从下一篇开始我们就开始讲述Hadoop的另一个核心模块——Yarn。关注专栏《破茧成蝶——Hadoop篇》查看相关系列的文章~


目录

一、Hadoop压缩概述

二、MapReduce支持的压缩编码

三、压缩方式简介

3.1 Gzip压缩

3.2 Bzip2压缩

3.3 Lzo压缩

3.4 Snappy压缩

四、压缩位置选择

五、压缩参数配置

六、压缩操作实例

6.1 数据流的压缩和解压缩

6.2 Map输出端采用压缩

6.3 Reduce输出端采用压缩


一、Hadoop压缩概述

       压缩技术能够有效减少HDFS的读写字节数,提高了网络带宽和磁盘空间的效率。在运行MapReduce程序时,IO操作、网络数据传输、Shuffle和Merge要花费大量的时间,尤其是数据规模很大和工作负载密集的情况下。因此,数据压缩显得非常重要。可以在MapReduce的任意阶段启用压缩。压缩技术虽然减少了磁盘IO,但同时增加了CPU运算负担。所以,压缩特性运行得当能提高性能,运用不当也会降低性能。对于运算密集型的job,要少用压缩;对于IO密集型的job,要多用压缩。

二、MapReduce支持的压缩编码

       为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器,如下所示:

       压缩性能比较:

三、压缩方式简介

3.1 Gzip压缩

       优点:压缩效率高,而且速度快。Hadoop本身支持,在应用中处理Gzip格式的文件和直接处理文本一样,大部分Linux系统都自带Gzip命令,使用比较方便。

       缺点:不支持Split。

       应用场景:当每个文件压缩之后在130M以内(一个块大小内)的都可以考虑使用Gzip压缩格式。

3.2 Bzip2压缩

       优点:支持Split,具有很高的压缩率,Hadoop本身自带,使用方便。

       缺点:压缩/解压速度慢.

       应用场景:适合对速度要求不高,但需要较高压缩率的时候。或者输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用的比较少的情况。或者对单个很大的文件文本想要压缩减少存储空间,同时又要支持Split,而且兼容之前的应用程序情况。

3.3 Lzo压缩

       优点:压缩/解压的速度较快,合理的压缩率,支持Split,是Hadoop中最流行的压缩格式,可以在Linux系统下安装lzop命令,使用方便。

       缺点:压缩率比Gzip要低,且Hadoop本身不支持,需要安装。在应用中对Lzo格式文件需要做一些特殊处理(为了支持Split需要建索引,还需要指定InputFormat为Lzo格式)。

       应用场景:应用于大文件,单个文件越大,Lzo优点越明显。

3.4 Snappy压缩

       优点:高速压缩速度和合理的压缩率。

       缺点:不支持Split,压缩率比Gzip要低,Hadoop本身不支持。

       应用场景:当MapReduce作业的Map输出数据比较大的时候,作为Map到Reduce的中间数据的压缩格式。或者作为一个MapReduce作业的输出和另外一个MapReduce作业的输入的压缩格式。

四、压缩位置选择

       压缩可以在MapReduce作用的任意阶段启动。在有大量数据并计划重复处理的情况下,应该考虑对输入进行压缩。然而,无需显示指定使用的编解码方式。Hadoop自动检查文件扩展名,如果扩展名能够匹配,就会用恰当的编解码方式对文件进行压缩和解压。否则,Hadoop就不会使用任何编解码器。当Map任务输出的中间数据量很大时,应考虑在此阶段采用压缩技术。这能显著改善内部数据的Shuffle过程,而Shuffle过程在Hadoop处理过程中是资源消耗最多的环节。如果发现数据量大造成网络传输缓慢,应该考虑使用压缩技术。可用于压缩Mapper输出的快速编解码器包括LZO或者Snappy。在Reducer阶段采用压缩技术能够减少要存储的数据量,因此降低所需的磁盘空间。当MapReduce作业形成作业链条时,因为第二个作业的输入也已经压缩,所以启用压缩同样有效。

五、压缩参数配置

六、压缩操作实例

6.1 数据流的压缩和解压缩

package com.xzw.hadoop.mapreduce.compress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.CompressionCodecFactory;
import org.apache.hadoop.io.compress.CompressionInputStream;
import org.apache.hadoop.io.compress.CompressionOutputStream;
import org.apache.hadoop.util.ReflectionUtils;

import java.io.*;

/**
 * @author: xzw
 * @create_date: 2020/8/22 14:19
 * @desc:
 * @modifier:
 * @modified_date:
 * @desc:
 */
public class TestCompress {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //压缩
        compress("e:/input/nginx_log", "org.apache.hadoop.io.compress.BZip2Codec");

        //解压缩
//        uncompress("e:/input/nginx_log.bz2");
    }

    /**
     * 压缩
     * @param filename 压缩的文件名
     * @param method 采用的压缩方法
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private static void compress(String filename, String method) throws IOException, ClassNotFoundException {
        //1、获取输入流
        FileInputStream fis = new FileInputStream(new File(filename));
        Class codeClass = Class.forName(method);
        CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codeClass, new Configuration());

        //2、获取输出流
        FileOutputStream fos = new FileOutputStream(new File(filename + codec.getDefaultExtension()));
        CompressionOutputStream cos = codec.createOutputStream(fos);

        //3、流对拷
        IOUtils.copyBytes(fis, cos, 1024*1024*5, false);

        //4、关闭资源
        cos.close();
        fos.close();
        fis.close();
    }

    /**
     * 解压缩
     * @param filename 需要解压的文件名
     * @throws IOException
     */
    private static void uncompress(String filename) throws IOException {
        //1、校验是否能解压缩
        CompressionCodecFactory factory = new CompressionCodecFactory(new Configuration());
        CompressionCodec codec = factory.getCodec(new Path(filename));

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

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

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

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

        //5、关闭资源
        cis.close();
        fos.close();
    }
}

       常用的压缩方法如下:

DEFLATE:org.apache.hadoop.io.compress.DefaultCodec
gzip:org.apache.hadoop.io.compress.GzipCodec
bzip2:org.apache.hadoop.io.compress.BZip2Codec

       运行一下看看结果:

6.2 Map输出端采用压缩

       这里采用《九、Hadoop核心组件之MapReduce》中的WordCount实例,要想实现Map输出端压缩,只需要在Driver类中加入如下两个属性即可:

// 开启map端输出压缩
configuration.setBoolean("mapreduce.map.output.compress", true);
// 设置map端输出压缩方式
configuration.setClass("mapreduce.map.output.compress.codec", BZip2Codec.class, CompressionCodec.class);

6.3 Reduce输出端采用压缩

       同样的还是采用之前的WordCount例子,只需要在Driver类中加上如下属性即可:

// 设置reduce端输出压缩开启
FileOutputFormat.setCompressOutput(job, true);

// 设置压缩的方式
FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class);

       本文到此也就结束了,你们在此过程中遇到了什么问题,欢迎留言,让我看看你们都遇到了哪些问题~

猜你喜欢

转载自blog.csdn.net/gdkyxy2013/article/details/108164116