MapReduce之数据压缩

Hadoop 数据压缩

概述

  1. 压缩的好处和坏处

    压缩的优点:以减少磁盘 IO、减少磁盘存储空间。

    压缩的缺点:增加磁盘 CPU 开销。

  2. 压缩原则

    运算密集型的 job,少用压缩

    注意:在运算密集型任务中,cpu 的占用较多,如果采取压缩可能会降低 cpu 性能,影响主线。

    IO 密集型的 Job,多用压缩

    注意:IO 密集型数据,频繁写入读取数据,采用压缩算法,可以减少 IO 时间。

MR 支持的压缩编码

  1. 压缩算法对比介绍

    压缩格式 Hadoop 自带? 算法 文件扩展名 是否可切片 换成压缩格式后,原来的程序是否需要修改
    DEFLATE 是,直接使用 DEFLATE .deflate 和文本处理一样,不需要修改
    Gzip 是,直接使用 DEFLATE .gz 和文本处理一样,不需要修改
    bzip2 是,直接使用 bzip2 .bz2 和文本处理一样,不需要修改
    LZO 否,需要安装 LZO .lzo 需要建索引,还需要指定输入格式
    Snappy 是,直接使用 Snappy .snappy 和文本处理一样,不需要修改
  2. 压缩性能的比较

    压缩算法 原始文件大小 压缩文件大小 压缩速度 解压速度
    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

    http://google.github.io/snappy/

    Snappy is a compression/decompression library. It does not aim for maximum compression, or compatibility with any other compression library; instead, it aims for very high speeds and reasonable compression. For instance, compared to the fastest mode of zlib, Snappy is an order of magnitude faster for most inputs, but the resulting compressed files are anywhere from 20% to 100% bigger.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.

压缩方式的选择

压缩方式选择是重点考虑:压缩/解压缩速度、压缩率(压缩后存储大小)、压缩后是否可以支持切片

  1. Gzip 压缩

    • 优点:压缩率比较高
    • 缺点:不支持 Split;压缩/解压速度一般
  2. Bzip2

    • 优点:压缩率高;支持 Split
    • 缺点:压缩/解压速度慢
  3. Lzo 压缩

    • 优点:压缩/解压速度比较快;支持 Split;
    • 缺点:压缩率一般;像支持切片需要额外创建索引。
  4. Snappy 压缩

    • 优点:压缩和解压缩速度快
    • 缺点:不支持 Split;压缩速率一般
  5. 压缩位置选择

    压缩可以在 MapReduce 作用的任意阶段使用

压缩参数配置

  1. 为了支持多种压缩/解压缩算法,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
  2. 要在 Hadoop 中启用压缩,可以配置如下参数

    参数 默认值 阶段 建议
    io.compression.codecs (在 core-site.xml 中配置) 无,这个需要在命令行输入 hadoop checknative 查看 输入压缩 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 的输入输出文件都是未压缩的文件,你仍然可以对 Map 任务的中间结果输出做压缩,因为它要写在硬盘并且通过网络传输到 Reduce 节点,对其压缩可以提高很多性能,这些工作只要设置两个属性即可,我们来看下代码怎么设置。

1.Map 输出端采用压缩

给大家提供的 Hadoop 源码支持的压缩格式有:BZip2Codec、DefaultCodec

package com.atguigu.mapreduce.compress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.compress.BZip2Codec;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * @author: fxl
 * @Description:
 * @Data:Create in  2021-10-20
 * @Modified By:
 */

public class WordCountDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        // 1 获取配置信息以及获取JOB对象
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        // 2 关联本Driver程序的jar
        job.setJarByClass(WordCountDriver.class);

        // 3 关联Mapper和Reducer的jar
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        // 4 设置Mapper输出的kv类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        4.1 设置Map端输出压缩
        // 开启map端输出压缩
        conf.setBoolean("mapreduce.map.output.compress"true);

        // 设置map端输出压缩方式
        conf.setClass("mapreduce.map.output.compress.codec", BZip2Codec.classCompressionCodec.class);


        // 5 设置最终输出的kv类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //job.setCombinerClass(WordCountCombiner.class);
        // 如果不设置InputFormat,它默认用的是TextInputFormat.class

        job.setInputFormatClass(CombineTextInputFormat.class);


        //虚拟存储切片最大值设置4m

        CombineTextInputFormat.setMaxInputSplitSize(job, 20971520);

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

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


        // 6 设置输入和输出路径 本地模式
        FileInputFormat.setInputPaths(job, new Path("E:\\MyFiles\\尚硅谷-大数据\\2-尚硅谷大数据技术之Hadoop3.x\\资料\\11_input\\hello.txt"));
        FileOutputFormat.setOutputPath(job, new Path("E:\\outputcompress02"));

//        FileInputFormat.setInputPaths(job, new Path(args[0]));
//        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        //7 提交job
        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }
}

Reduce 输出端采用压缩

只需修改驱动代码就可以

package com.atguigu.mapreduce.compress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.compress.BZip2Codec;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * @author: fxl
 * @Description:
 * @Data:Create in  2021-10-20
 * @Modified By:
 */

public class WordCountDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        // 1 获取配置信息以及获取JOB对象
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);

        // 2 关联本Driver程序的jar
        job.setJarByClass(WordCountDriver.class);

        // 3 关联Mapper和Reducer的jar
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        // 4 设置Mapper输出的kv类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

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


        // 5 设置最终输出的kv类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //job.setCombinerClass(WordCountCombiner.class);
        // 如果不设置InputFormat,它默认用的是TextInputFormat.class

        job.setInputFormatClass(CombineTextInputFormat.class);


        //虚拟存储切片最大值设置4m

        CombineTextInputFormat.setMaxInputSplitSize(job, 20971520);

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

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


        // 6 设置输入和输出路径 本地模式
        FileInputFormat.setInputPaths(job, new Path("E:\\MyFiles\\尚硅谷-大数据\\2-尚硅谷大数据技术之Hadoop3.x\\资料\\11_input\\hello.txt"));
        FileOutputFormat.setOutputPath(job, new Path("E:\\outputcompress02"));

//        FileInputFormat.setInputPaths(job, new Path(args[0]));
//        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        //7 提交job
        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);
    }
}

posted @ 2021-11-15 13:58  逆十字  阅读(167)  评论(0)    收藏  举报