10)Hadoop数据压缩

概述
  • 压缩技术能有效减少底层存储系统(HDFS)的读写字数。压缩提高了网络带宽和磁盘空间的效率。在运行MR程序时,I/O操作、网络数据传输、Shuffle、Merge要花费大量时间,尤其是=在数据规模很大和工作负载很密集的时候,数据压缩显得非常重要

  • 鉴于磁盘IO和网络带宽是Hadoop的宝贵资源,数据压缩对于节省资源,最小化磁盘I/O和网络传输非常有帮助,可以在任意MapReduce阶段启用压缩。不过,尽管压缩和解压缩所占CPU开销不多,但其性能的提升和资源的节省并非没有代价

  • 压缩的基本原则:

    • 运算密集型的job,少用压缩
    • IO密集型的job,多用压缩
  • MR支持的压缩编码:

    压缩格式hadoop自带?算法文件扩展名是否可切分换成压缩格式后,原来的程序是否需要修改
    DEFLATE是,直接使用DEFLATE.deflate和文本处理一样,不需要修改
    Gzip是,直接使用DEFLATE.gz和文本处理一样,不需要修改
    bzip2是,直接使用bzip2.bz2和文本处理一样,不需要修改
    LZO否,需要安装LZO.lzo需要建索引,还需要指定输入格式
    Snappy否,需要安装Snappy.snappy和文本处理一样,不需要修改
  • 为了支持多种压缩/解压缩算法,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
  • 压缩性能的比较

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

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压缩:
      当每个文件压缩之后在130M以内(一个块大小之内),都可以选择Gizp压缩格式,例如说一天或一个小时的的日志压缩成一个Gizp文件。

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

    • LZO压缩:
      一个很大的文本文件,压缩之后还大于200M以上可以考虑,而且单个文件越大,Lzo的优势越明显。

    • Snappy压缩:
      当MapReduce的Map端的输出的数据比较大时,作为Map到Reduce的中间的数据的压缩格式,或者作为一个MapReduce的输出和另一个MapReduce的输入。

  • 压缩位置的选择:

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

    参数默认值阶段建议
    o.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中配置)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
    mapreduce.output.fileoutputformat.compress.type(在mapred-site.xml中配置)RECORDreducer输出SequenceFile输出使用的压缩类型:NONE和BLOCK
压缩案例:
数据流的压缩和解压缩
  • 测试bzip2压缩方式:
public class TestCompress {

    public static void main(String[] args) throws Exception {
        compress("e:/hello.txt","org.apache.hadoop.io.compress.BZip2Codec");
//    decompress("e:/hello.txt.bz2");
    }

    // 1、压缩
    private static void compress(String filename, String method) throws Exception {

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

        Class codecClass = Class.forName(method);

        CompressionCodec codec = (CompressionCodec) ReflectionUtils.newInstance(codecClass, 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();
    }

    // 2、解压缩
    private static void decompress(String filename) throws FileNotFoundException, IOException {

        // (0)校验是否能解压缩
        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;
        }

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

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

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

        // (4)关闭资源
        cis.close();
        fos.close();
    }
}
Map输出端采用压缩
  • 即使MapReduce的输入输出文件都是未压缩的文件,仍然可以对Map任务的中间结果输出做压缩,因为它要写在硬盘并且通过网络传输到Reduce节点,对其压缩可以提高很多性能,这些工作只要设置两个属性即可,代码设置如下:

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

public class WordCountDriver {

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

        Configuration configuration = new Configuration();

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

        Job job = Job.getInstance(configuration);

        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 ? 1 : 0);
    }
}
  • Mapper保持不变:
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{

    Text k = new Text();
    IntWritable v = new IntWritable(1);

    @Override
    protected void map(LongWritable key, Text value, Context context)throws IOException, InterruptedException {

        // 1 获取一行
        String line = value.toString();

        // 2 切割
        String[] words = line.split(" ");

        // 3 循环写出
        for(String word:words){
            k.set(word);
            context.write(k, v);
        }
    }
}
  • Reducer保持不变
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{

    IntWritable v = new IntWritable();

    @Override
    protected void reduce(Text key, Iterable<IntWritable> values,
                          Context context) throws IOException, InterruptedException {

        int sum = 0;

        // 1 汇总
        for(IntWritable value:values){
            sum += value.get();
        }

        v.set(sum);

        // 2 输出
        context.write(key, v);
    }
}
Reduce输出端采用压缩(基于WordCount案例处理)
  • 修改驱动
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        Configuration configuration = new Configuration();

        Job job = Job.getInstance(configuration);

        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?1:0);
    }
}
  • Mapper和Reducer保持不变
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值