不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)

讲解视频

学习Hadoop搞明白Shuffle的原理是非常重要的,然而相信很多人看了《Hadoop权威指南4》好几遍,也没有真正搞明白它真正的原理。看完这篇文章,相信会对你理解Shuffle有很大的帮助。 

官方给的定义:系统执行排序、将map输出作为输入传给reducer的过程称为Shuffle。(看完是不是一脸懵逼)

通俗来讲,就是从map产生输出开始到reduce消化输入的整个过程称为Shuffle。如下图用黑线框出的部分:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第1张图片

圆形缓冲区介绍:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第2张图片

 

每一个map任务都会有一个圆形缓冲区。默认大小100MB(io.sort.mb属性)阈值0.8也就是80MB(io.sort.spill.percent属性指定) ,

 

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第3张图片

一旦达到阈值一个后台线程开始把内容写到(spill)磁盘的指定目录mapred.local.dir下的新建的一个溢出写文件。写入磁盘前先partition、sort、[combiner]。一个map task任务可能产生N个磁盘文件。

map task运算完之后,产生了N个文件,然后将这些文件merge合成一个文件。

如果N=2,合成的新文件写入磁盘前只经过patition(分区)和sort(排序)过程,不会执行combiner合并(无论是否指定combiner类),如下图所示:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第4张图片

如果N>=3,合成的新文件写入磁盘前经过patition(分区)、sort(排序)过和combiner合并(前提是指定了combiner类),如下图所示:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第5张图片

思考:为什么只有当N>=3时,合成文件才会执行combiner呢?

这是因为如果N<3时,执行combiner虽然减少了文件的大小,但是同时产生了一定的系统开销。由于减少的文件大小不大,权衡利弊后,确定N<2时不在执行combiner操作。

当该map task全部执行完之后,对应的reduce task将会拷贝对应分区的数据(该过程称为fetch),如下图所示:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第6张图片

其它的map task任务完成后,对应的reduce task也同样执行fetch操作,如下图所示:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第7张图片

每个map任务的完成时间可能不同,因此只要有一个任务完成,reduce任务就开始复制其输出。该阶段被称为reduce的复制阶段。reduce任务有少量复制线程,因此能够并行取得map输出。默认值是5个线程,但这个默认值可以通过设置mapred.reduce.parallel.copies属性改变。

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第8张图片

复制完所有map输出后,reduce任务进入合并阶段,该阶段将合并map输出,并维持其顺序排序(相当于执行了sort),如果指定了combiner,在写入磁盘前还会执行combiner操作。

那么具体是如何合并的呢?

合并因子默认是10,可以通过io.sort.factor属性设置。合并过程是循环进行了,可能叫经过多趟合并。目标是合并最小数量的文件以便满足最后一趟的合并系数。假设有40个文件,我们不会在四趟中每趟合并10个文件从而得到4个文件。相反,第一趟只合并4个文件,随后的三趟分别合并10个文件。再最后一趟中4个已合并的文件和余下的6个(未合并的)文件合计10个文件。具体流程如下图所示:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第9张图片

注意:这并没有改变合并次数,它只是一个优化措施,目的是尽量减少写到磁盘的数据量,因为最后一趟总是直接合并到reduce。

看到这里您是否理解了Shuffle的具体原理呢,如果没有,也没有关系,接下来我们通过一个wordcount案例再将整个流程梳理一遍。

首先map任务的代码如下:

public class WCMapper extends Mapper {
      public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException {
        String line = ivalue.toString();    String words[] = line.split(" ");    for (String word : words) {
          context.write(new Text(word), new LongWritable(1));    }  }}

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第10张图片

在分区(分区规则:按首字母分四个区,分别为a-i,j-q,r-z,其它)的过程中,会将相同的单词合并到一起,将出现次数用逗号隔开,如上图所示。注意此时还没有排序。分区代码如下:

package cn.geekmooc;import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Partitioner;public class WCPatitioner extends Partitioner {
      @Override  public int getPartition(Text key, LongWritable value, int numPartitions) {
        int first_char = key.charAt(0);    if(first_char>=97&&first_char<=105){
          return 0;    }else if(first_char>=106&&first_char<=113){
          return 1;    }else if(first_char>=114&&first_char<=122){
          return 2;    }else{
          return 3;    }  }}

接着执行排序操作,默认排序规则是按照key的字典升序排序,当然你也可以指定排序规则,排序后如下图所示:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第11张图片

接下来执行combiner操作,将每个单词后续的1求和,WCCombiner类代码如下:

package cn.geekmooc;import java.io.IOException;import java.util.Iterator;import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Reducer;public class WCCombiner extends Reducer {
      @Override  protected void reduce(Text key, Iterable values,      Reducer.Context context) throws IOException, InterruptedException {
        System.out.println(key.toString()+":"+values.toString());    long count = 0;    Iterator iter = values.iterator();    while(iter.hasNext()){
          count += iter.next().get();    }    context.write(key, new LongWritable(count));  }}

combiner的结果如下图所示

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第12张图片

map任务执行完,产生N个spill文件,接着对N个文件进行合并,分以下两种情况:

1.N<3,无论是否指定combiner类,合并文件时都不会执行combiner

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第13张图片

2.N>=3,如果指定了combiner类将执行combiner操作,如下图:

 

接下来进入fetch(或copy)阶段

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第14张图片

然后在reduce端进行合并

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第15张图片

然后执行最后一趟合并,并将结果直接传给reduce

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第16张图片

reduce类代码如下:

package cn.geekmooc;import java.io.IOException;import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Reducer;public class WCReducer extends Reducer {
      @Override  protected void reduce(Text key, Iterable values,      Reducer.Context context) throws IOException, InterruptedException {
        System.out.println(key.toString()+":"+values.toString());    long count = 0;    for (LongWritable val : values) {
          count += val.get();    }    context.write(key, new LongWritable(count));  }}

reduce task执行后,输出结果:

不懂Hadoop心脏Shuffle的原理这一篇就够了(含讲解视频)_第17张图片

 

你可能感兴趣的:(Hadoop,大数据,Java,Hadoop,Shuffle,MapReduce)