MapReduce高级
MapReduce会确保每个reducer的输入都是按键排序的。从map方法输出数据开始、到作为输入数据传给reduce方法的过程称为shuffle。在此,我们将学习shuffle是如何工作的,因为它有助于我们理解工作机制(如果需要优化MapReduce程序)。shuffle属于不断被优化和改进的代码库的一部分,因此会随着版本的不同,细节上可能会发生变量。不管怎样,从许多方面来看,shuffle是MapReduce的“心脏“,是奇迹发生的地方。
Hadoop权威指南
map方法开始产生输出数据时,并不是简单地将它写到磁盘。这个过程非常复杂,它利用缓冲的方式写到内存并出于效率的考虑进行预排序。
每个map任务都会有一个环形内存缓冲区用于存储map的输出数据。在默认情况下,缓冲区的大小为100MB,这个值可以通过mapreduce.task.io.sort.mb属性来调整。一旦缓冲区的内容达到阙值(默认是0.8,或者是80%,属性是mapreduce.map.sort.spill.percent),一个后台线程便开始把内容溢写(spill)到磁盘里,这个位置由属性mapreduce.cluster.local.dir来指定的。在将数据溢写到磁盘过程中,map的输出数据继续写到缓冲区,但如果在此期间缓冲区被填满,map会被阻塞直到写磁盘过程完成。
在写磁盘之前,线程会根据分区器的逻辑把数据划分为不同的分区(partition)。然后,在每个分区中,后台线程会按键进行内存中排序(QuickSort,默认是字典顺序)。如果指定了一个combiner函数,它就在排序后的输出上运行。运行combiner函数使得map输出结果更紧凑,因此减少写到磁盘的数据和传递给reducer的数据。
每次内存缓冲区达到溢出阖值,就会新建一个溢出文件(spill file),因此在map任务写完其最后一个输出记录之后,可能会有几个溢出文件。在MapTask任务完成之前,多个溢出文件被合并成一个已分区且已排序的输出文件。配置属性mapreduce.task.io.sort.factor控制着一次最多能合并多少个文件,默认值是10。
如果至少存在3个溢出文件(通过mapreduce.map.combine.minspills属性设置)时,则combiner就会在输出文件写到磁盘之前再次运行。combiner可以在输入上反复运行,但并不影响最终结果。如果只有1或2个溢出文件,那么由于map输出规模减少,因而不值得调用combiner产生开销,因此不会为该map输出再次运行combiner。
为了使写磁盘的速度更快,节约磁盘空间,并且减少传给reducer的数据量,在溢写到磁盘的过程中对数据进行压缩往往是个很好的主意。在默认情况下,输出是不压缩的,但只要将mapreduce.map.output, compres