• Hadoop3教程(二十一):MapReduce中的压缩


    (123)压缩概述

    压缩也是MR中比较重要的一环,其可以应用于Map阶段,比如说Map端输出的文件,也可以应用于Reduce阶段,如最终落地的文件。

    压缩的好处,是减少磁盘的IO以及存储空间。缺点也很明显,就是极大增加了CPU的开销(频繁计算带来的频繁压缩与解压缩)。

    压缩的基本原则:

    • 对运算密集型job,少用压缩;(计算时需要解压缩,计算完需要压缩,受不了)
    • 对IO密集型Job,多用压缩。

    MR支持很多种压缩算法,常用的有以下几个:

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

    支持切片的话,使用上会更方便很多。

    压缩性能的比较如下:

    压缩算法原始文件大小压缩文件大小压缩速度解压速度
    gzip8.3GB1.8GB17.5MB/s58MB/s
    bzip28.3GB1.1GB2.4MB/s9.5MB/s
    LZO8.3GB2.9GB49.3MB/s74.6MB/s

    据说最好的还是Google开发的snappy,其官网介绍它的压缩速度是250MB/s,解压缩速度是500MB/s。

    那在生产环境下,该如何选择合适的压缩方式呢?

    一般是重点考虑以下几点:

    • 压缩/解压缩速度;
    • 压缩率,即压缩后的文件大小;
    • 压缩后是否还支持切片。

    结合这几点,我们再回头看这几种压缩算法。

    Gzip压缩:压缩率比较高,但是压缩/解压缩速度一般,且不支持切片;

    Bzip2压缩,压缩率非常高,且支持切片,但是压缩/解压缩速度极慢;

    Lzo压缩,压缩/解压缩速度非常快,且支持切片,但是压缩率一般;不过Lzo需要额外创建索引之后,才能支持切片。

    Snappy压缩,压缩和解压缩速度极快,但不支持切片,压缩率一般。

    压缩可以在MapReduce的任意阶段启用,一共三个阶段,即Map的输入端、Map到Reduce部分、Reduce的输出端。

    在Map阶段启用

    在Map的输入端启用压缩时:

    不需要显式指定使用的编解码方式,Hadoop会自动通过文件扩展名,来选择合适的编解码方式。

    同时,需要注意,如果数据量小于块大小的话,则可以考虑压缩、解压缩速度比较快的算法,如LZO、snappy;如果数据量大于块大小的话,则可以重点考虑支持切片的算法,如Bzip2和LZO。

    在Mapper的输出端启用压缩时:

    这里启用压缩,主要是为了减少MapTask和ReduceTask之间的网络IO,所以可以选择重点考虑压缩和解压缩快的LZO、snappy等。

    在Reduce阶段启用

    在Reducer的输出端启用压缩时:

    如果输出的数据是需要永久保存,那么可以采用压缩率比较高的算法,以减少存储的空间;

    如果是作为下一个MapReduce的输入,那么可以考虑数据量和是否支持切片。

    (124)压缩案例实操

    讲怎么写压缩代码的,此处只做了解,所以基本是直接复制教程文档。

    为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器

    压缩格式对应的编码/解码器
    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

    要在Hadoop中启用压缩,可以配置如下参数

    参数默认值阶段建议
    io.compression.codecs (在core-site.xml中配置)无,这个需要在命令行输入hadoop checknative查看输入压缩Hadoop使用文件扩展名判断是否支持某种编解码器
    mapreduce.map.output.compress(在mapred-site.xml中配置)falsemapper输出这个参数设为true启用压缩
    mapreduce.map.output.compress.codec(在mapred-site.xml中配置)org.apache.hadoop.io.compress.DefaultCodecmapper输出企业多使用LZO或Snappy编解码器在此阶段压缩数据
    mapreduce.output.fileoutputformat.compress(在mapred-site.xml中配置)falsereducer输出这个参数设为true启用压缩
    mapreduce.output.fileoutputformat.compress.codec(在mapred-site.xml中配置)org.apache.hadoop.io.compress.DefaultCodecreducer输出使用标准工具或者编解码器,如gzip和bzip2

    抄一下案例。

    如何在Map输出端启用压缩

    假如想Mapper输出端启用压缩,只需要调整驱动类即可,Mapper和Reducer类不需要做特殊处理,跟正常一样就可以。

    package com.atguigu.mapreduce.compress;
    import java.io.IOException;
    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.io.compress.GzipCodec;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    public class WordCountDriver {
    
    	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    
    		Configuration conf = new Configuration();
    
    		// 开启map端输出压缩
    		conf.setBoolean("mapreduce.map.output.compress", true);
    
    		// 设置map端输出压缩方式
    		conf.setClass("mapreduce.map.output.compress.codec", BZip2Codec.class,CompressionCodec.class);
    
    		Job job = Job.getInstance(conf);
    
    		job.setJarByClass(WordCountDriver.class);
    
    		job.setMapperClass(WordCountMapper.class);
    		job.setReducerClass(WordCountReducer.class);
    
    		job.setMapOutputKeyClass(Text.class);
    		job.setMapOutputValueClass(IntWritable.class);
    
    		job.setOutputKeyClass(Text.class);
    		job.setOutputValueClass(IntWritable.class);
    
    		FileInputFormat.setInputPaths(job, new Path(args[0]));
    		FileOutputFormat.setOutputPath(job, new Path(args[1]));
    
    		boolean result = job.waitForCompletion(true);
    
    		System.exit(result ? 0 : 1);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    如何在Reduce端启用压缩

    假如想Reducer输出端启用压缩:

    package com.atguigu.mapreduce.compress;
    import java.io.IOException;
    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.DefaultCodec;
    import org.apache.hadoop.io.compress.GzipCodec;
    import org.apache.hadoop.io.compress.Lz4Codec;
    import org.apache.hadoop.io.compress.SnappyCodec;
    import org.apache.hadoop.mapreduce.Job;
    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
    
    public class WordCountDriver {
    
    	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    		
    		Configuration conf = new Configuration();
    		
    		Job job = Job.getInstance(conf);
    		
    		job.setJarByClass(WordCountDriver.class);
    		
    		job.setMapperClass(WordCountMapper.class);
    		job.setReducerClass(WordCountReducer.class);
    		
    		job.setMapOutputKeyClass(Text.class);
    		job.setMapOutputValueClass(IntWritable.class);
    		
    		job.setOutputKeyClass(Text.class);
    		job.setOutputValueClass(IntWritable.class);
    		
    		FileInputFormat.setInputPaths(job, new Path(args[0]));
    		FileOutputFormat.setOutputPath(job, new Path(args[1]));
    		
    		// 设置reduce端输出压缩开启
    		FileOutputFormat.setCompressOutput(job, true);
    
    		// 设置压缩的方式
    	    FileOutputFormat.setOutputCompressorClass(job, BZip2Codec.class); 
    //	    FileOutputFormat.setOutputCompressorClass(job, GzipCodec.class); 
    //	    FileOutputFormat.setOutputCompressorClass(job, DefaultCodec.class); 
    	    
    		boolean result = job.waitForCompletion(true);
    		
    		System.exit(result?0:1);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    参考文献

    1. 【尚硅谷大数据Hadoop教程,hadoop3.x搭建到集群调优,百万播放】
  • 相关阅读:
    Scss--@mixin--使用/实例
    接口自动化用例设计总结
    vue单页面改造多页面应用
    使用 PHP、PDO 和 MySQL 的 CRUD 应用程序
    【Unity学习笔记】基础游戏单位GameObject中常用的属性和API
    【MySQL进阶】SQL性能分析
    排序之快速排序
    【Linux】进程控制-进程程序替换
    人人都是艺术家!AI工具Doodly让潦草手绘变精美画作
    数据结构之杨辉三角
  • 原文地址:https://blog.csdn.net/wlh2220133699/article/details/133896349