浅析Hadoop 的压缩

前言:

探索开启Hadoop的压缩后,有哪些过程中 调用了 压缩 和 解压?


一、 从 Hadoop 的 Map/Reduce 框架 处理流程,有如下 三个阶段 和 压缩 相关

1.  MAP 的 输入数据为压缩格式的文件,这个在FileInput的时候会解压。
2.  MapOutput 写本地文件系统阶段,这个需要配置,默认是false, 不压缩。

mapreduce.map.output.compress.codec

org.apache.hadoop.io.compress.DefaultCodec

mapreduce.output.fileoutputformat.compress

false

mapreduce.output.fileoutputformat.compress.type

RECORD

3. FileOutput 写 HDFS文件系统 阶段,这个需要配置,默认是false, 不压缩。但是即使你配置了有的test case(如Terasort)的FileOutput 为压缩格式,也不会生效。为什么? 因为代码里没调用。为什么没调用?因为为了满足TeraValid快速验证。

mapreduce.output.fileoutputformat.compress.codec

org.apache.hadoop.io.compress.DefaultCodec


二、 从 Hadoop 的 代码 执行流程看 压缩 是怎么实现的 (流程图请参考  blog https://blog.csdn.net/don_chiang709/article/details/80597323)

实际上在segment数据的反复读写过程中都有调用这个压缩算法。

1.  MAP 的 输入数据为压缩格式的文件: 参考 SequenceFile.java 的 init()

2.  MapOutput 写本地文件系统阶段:  数据从 环形 buffer (io.sort.mb )出来后,最终都会调用 Merger.java里的merge,是调用一次还是多次,这个要看memory配置是否足够了。数据的 压缩参数随 每个 segment 的构造已经传入,这样segment的读写都可以随时调用 设置的 压缩类 了。另外 Merger.java 的 reader 成员包含了 压缩 类型,其 初始化在 init() 函数里,如下:

 void init(Counters.Counter readsCounter) throws IOException {
      if (reader == null) {
        FSDataInputStream in = fs.open(file);
        in.seek(segmentOffset);
        in = CryptoUtils.wrapIfNecessary(conf, in);
        reader = new Reader(conf, in,
            segmentLength - CryptoUtils.cryptoPadding(conf),
            codec, readsCounter);

      }

     (这个过程包含压缩解压调用)为什么这里的reader也需要传入压缩类型呢?因为多次merge就需要反复读写segment了。

  而 MAP 任务的最终结果会调用Merger.java里 MergeQueue类的 merge方法,在merge方法里new Writer并使用传入参数codec,如下:

     Writer writer = new Writer(conf, out, keyClass, valueClass,
              codec, writesCounter, true);
          writeFile(this, writer, reporter, conf);
          writer.close();

(这个过程包含压缩解压调用)所以MAP任务的最终结果(reduce任务的输入)按指定的 压缩 类型 写到了本地文件系统。

(这个过程包含压缩解压调用)而reduce 的输入需要解压 MAP任务的数据,这个是在 InMemoryMapOutput.java 的 shuffle函数里实现如下;

    // Are map-outputs compressed?
    if (codec != null) {
      decompressor.reset();
      input = codec.createInputStream(input, decompressor);
    }

  OnDiskMapOutput.java的shuffle函数里直接写磁盘,没使用时不需要解压。

(这个过程包含压缩解压调用)reduce 的 中间结果 merge跟 MAP的 merge是调用同一个函数(Merger.java里 MergeQueue类的 merge方法),这里 是调用一次 还是 多次 压缩/解压缩,这个要看memory配置是否足够了。

reduce 的 中间结果 作为 reduce 函数的 输入,还是利用segment的压缩 和 解压缩类型调用。(这个过程包含压缩解压调用)

3. FileOutput 写 HDFS文件系统 阶段:这个的最终看FileOutput里的writer实现。是否有检查用户设置了压缩类型,write时去调用相应的 压缩类 。而 terasort 没有调用压缩接口(参考TeraOutputFormat.java),如下:

    public synchronized void write(Text key, 
                                   Text value) throws IOException {
      out.write(key.getBytes(), 0, key.getLength());
      out.write(value.getBytes(), 0, value.getLength());
    }


三、 总结

开启Hadoop的压缩后,不是简单的一个压缩过程。在Map/Reduce 任务的merge过程中村子反复 压缩 和 解压的调用。


你可能感兴趣的:(Compression,Hadoop)