当使用指定的组合器运行MapReduce作业时,组合器是否在排序阶段运行?我知道,对于每次溢出,组合器都是在映射器输出上运行的,但是在合并排序的中间步骤中运行似乎也是有益的。我在这里假设,在排序的某些阶段,一些等价键的映射器输出在某个时刻保存在内存中。
如果这目前没有发生,是有特殊的原因,还是只是一些没有实现的东西?
提前感谢!
合并器是用来节省网络带宽的。
mapoutput直接排序:
sorter.sort(MapOutputBuffer.this, kvstart, endPosition, reporter);
这发生在实际映射完成之后。在遍历缓冲区期间,它检查是否设置了组合器,如果设置了,则合并记录。如果没有,则直接溢出到磁盘上。
重要的部分在MapTask
中,如果你想自己看的话。
sorter.sort(MapOutputBuffer.this, kvstart, endPosition, reporter);
// some fields
for (int i = 0; i < partitions; ++i) {
// check if configured
if (combinerRunner == null) {
// spill directly
} else {
combinerRunner.combine(kvIter, combineCollector);
}
}
这是节省磁盘空间和网络带宽的正确阶段,因为很可能必须传输输出。在合并/洗牌/排序阶段,这是没有好处的,因为与在map完成时运行的组合器相比,你必须处理更多的数据量。
注意,web界面上显示的排序阶段是误导的。
有两种运行Combiner的机会,都是在处理的映射端。(一个非常好的在线参考来自Tom White的"Hadoop:权威指南"- https://www.inkling.com/read/hadoop-definitive-guide-tom-white-3rd/chapter-6/shuffle-and-sort)
第一个机会出现在map端,在完成每个分区的内存中按键排序之后,并且在将这些排序的数据写入磁盘之前。此时运行Combiner的动机是减少最终写入本地存储的数据量。通过在这里运行Combiner,我们还减少了在下一步中需要合并和排序的数据量。所以对于最初发布的问题,是的,组合器已经在这个早期步骤中应用了。
第二个机会出现在合并和排序溢出文件之后。在这种情况下,运行Combiner的动机是减少最终通过网络发送到reducer的数据量。此阶段受益于早期的Combiner应用程序,它可能已经减少了此步骤要处理的数据量。
组合器只会按照你理解的方式运行。
我怀疑组合器只以这种方式工作的原因是它减少了发送到减少器的数据量。在许多情况下,这是一个巨大的收获。同时,在reducer中,数据已经在那里了,无论你是在排序/合并还是在你的reduce逻辑中组合它们,在计算上都不重要(要么现在做,要么以后做)。
所以,我想我的观点是:你可以通过合并获得收益,就像你在合并中所说的那样,但它不会像映射端组合器那样多。
我没有看过代码,但是参考了Hadoop: Tom White第3版的最终指南,它确实提到如果指定了组合器,它将在reducer的合并阶段运行。以下是节选自原文:
"如果map输出足够小,则将其复制到reduce任务JVM的内存中(缓冲区的大小由mapred.job.shuffle.input.buffer控制。百分比,指定用于此目的的堆的比例);否则,它们将被复制到磁盘。当内存缓冲区达到阈值大小时(由百分比),或者达到映射输出的阈值数量(mapred.inmem.merge.threshold),它被合并并溢出到磁盘。如果指定了一个组合符,它将在合并期间运行,以减少写入磁盘的数据量。"