前言:
探索开启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
segmentLength - CryptoUtils.cryptoPadding(conf),
codec, readsCounter);
}
(这个过程包含压缩解压调用)为什么这里的reader也需要传入压缩类型呢?因为多次merge就需要反复读写segment了。
而 MAP 任务的最终结果会调用Merger.java里 MergeQueue类的 merge方法,在merge方法里new Writer并使用传入参数codec,如下:
Writer
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过程中村子反复 压缩 和 解压的调用。