hadoop的心脏–shuffle过程解析

来源:互联网 发布:linux kvm教程 编辑:程序博客网 时间:2024/06/11 07:38

再上一次我们提到,shuffle是MapReduce的心脏,是奇迹发生的地方,这次我们来详细的探讨一下shuffle的真个过程。MapReduce确保每一个reducer是的输入都是按照键值Key排序的,这里排序主要是依据当前Key继承了Comparable类,有时候为了加快排序的速度,也会自定义一个内部类Comparator。系统执行排序的过程就是称为shuffle。学习shuffle的工作机制有助于我们理解mapreduce的工作机制。shuffle属于不断的被优化和改进代码库的一部分,也是在不断的发生着变化

  1. map


map函数开始产生输出的时候,是通过run()方法进行操作。但是这个时候的数据并不是直接的写到本地磁盘上面去,二是先写到内存的缓冲区中去,他利用缓冲的缓冲的方式吧数据写到内存,并且以此同时按照key对数据进行排序。每一个map任务都有一个唤醒的缓冲区用于任务暑促。在默认的情况下缓冲区的大小为100M,该数值通过io.sort.mb属性可以进行设置,对于这个缓冲区,当脸面存放的数据大小达到80%,也就是80M的时候就可以溢写到本地磁盘,从而进行数据本地化,在这如果我们把io.sort.mb这个数值设置的很大,当然可以在很大的程度上加快job的运行速度。80%的这个数值是在io.spill.percent中进行设置。这里的spill过程由一个专门的后台线程来实现,在spill的过程中间,map输出继续写到内存,但是在此期间缓冲期被填满,则map数据写到缓冲的任务会被阻塞,直到整个过程完成。 溢出写的过程按照轮回询问的方式把内容写到mapreduce.local.dir的目录下



在写磁盘之前,写成首先会根据每个数据对最终所在的reduce端的位置,用partition进行分区,在每个分区的过程中后台线程按照键值进行排序。这里会有一个对数据的优化,如果也已运行combiner,则会运行combiner把数据进行合并,减少IO磁盘的读写,Combiner可以运行多次,但是需要注意的是,他的运行不可以最终影响到程序的结果。运行combiner使得map的输出结果更加的紧凑。
这里我们来看一下partitioner的代码。他的作用就是,把相同key所对应的数据放到同一个reducer中进行处理。

public class MyPartitioner extendsPartitioner {@Overridepublic int getPartition(Text key, IntWritable value, int numPartitions) {String strValue = key.toString().substring(0, 1);可以看到就是把具有相同数值的数据放到同意文件if (strValue.matches("[a-z]")) {return 0 % numPartitions;}if (strValue.matches("[A-Z]")) {return 1 % numPartitions;}if (strValue.matches("[0-9]")) {return 2 % numPartitions;}return 3 % numPartitions;}



每次内存缓冲区达到溢写的阙值,都会重新的建立一个spill文件,因此在map任务写完最后一个文件后会产生好几个spill文件。在任务完成之前,这几个spill文件会被合成一个已经分区切排序的文件。在属性值io.sort.factor中间控制着每次最终可以合并多少个文件。默认的是指是10.追忆,如果spill的文件个数大于3,则就会在输出文件写到磁盘的时候再次进行combiner,减小数据。但是只有两个文件,就没有必要进行combiner。这样的开销不值得。



压缩map输出写到ip俺的过程中如果对数据进行压缩往往是一个不错的注意,因为这样会把些磁盘的速度加快。节约磁盘的空间,并且减少给reducer的数量。在默认的情况下,输出不会进行压缩,但是如果conf.set("mapred.compress.map.output",true)就可以实现吧数据进行compress。reducer通过HTTP方式得到数据文件的分区。用于文件分区的工作线程 的输血量由tracker.http.threads属性控制,默认的数值是40.这个数据在hadoop2中是不合适的,因为这个数据是基于机器本身的处理器的个数设定的


  1. reduce


现在我们来谈论reducer端部分。map输出文件位于马屁端任务的tsakTrackerde bendi cipan .map会把数据写到maptask任务所在的磁盘,但是reducer却不会这么做。Reducer任务需要集群上若干个map任务输出座位其特殊的分区文件。每一个map所需要的时间不尽相同,因此只要有一个map完成reducer任务就会开始复制其输出。这就是reducer的复制阶段。reducer端会有一定数量的复制线程,因此能够并行的取出map的输出。默认的线程数目是5. 如果map的输出相当的小,就会复制到reduce任务jvm内存中否则即使马屁输出会被本地化到磁盘。一旦内存的缓冲区达到阙值或者达到马屁输出的阙值,则会合并后一些到本地的磁盘。随着磁盘上副本数据的增多,后台线程会把他们合并成为更大的,排序好饿文件。这会为排序的文件节省一些时间。复制完所有的map输出之后就是进行reducer程序,开始合并阶段。这个阶段将合并map的输出,并且维持其顺序排序。这是循环进行的。例如100个map输出,每次合并10个,则会合并10次。 在最后阶段,就是reducer阶段了。直接把数据输入reducer函数,从而省略了一次磁盘写的过程。具体是这样的。例如有100个文件,合并的时候是在第一次合并5个文件,其他的9此每次合并10各个文件,最后一次把中合并的文件和第一的剩下的文件一起写到磁盘。


本文转载自:hadoop的心脏–shuffle过程解析


0 0
原创粉丝点击