·  MapReduce是怎样为数据进行分组,整合等操作的呢?这就涉及到Map和Reduce在中间十分关键的衔接部分Shuffle。
上面介绍了Map 和 Reduce的各自的任务和总的流程,MapReduce是怎样为数据进行分组,整合等操作的呢?这就涉及到Map和Reduce在中间十分关键的衔接部分Shuffle。
  什么是shuffle?shuffle原意是洗牌,混乱。而在MapReduce中shuffle却是将一些凌乱的数据规整成有一定规则的过程。Shuffle是横跨MapReduce的两端。

shuffle ess_shuffle ess

下面详细介绍一下shuffle的运行过程:
  
  在Mapper中的shuffle
  
  1.当MapTask获取到Split之后按行读取数据
  
  2.每读取一行调用一次map方法
  
  3.每一行经过map方法处理以后,会产生一个或者多个key-value结果
  
  4.Key-value的数据会暂时存到一个环形的缓冲区,这个缓冲区维系在内存中。
  
  5.在缓冲区中会对数据进行分区-partition, 排序-sort, 合并-combine操作
  
  6.当缓冲区使用在达到阈值(已使用缓冲区/缓冲区的总量,默认是0.8),将缓冲区的数据写到当前的磁盘中(spill—溢写),保存数据的格式—溢写。
  
  7.对于单个溢写文件而言,里面的数据是分好区排好序的,但是对于整体所有的溢写文件而言是无序的。
  
  8.等到所有的数据写完,会将所有的溢写文件进行一次合并(merge),合并到一个新的分区并且排序的文件中
  
  9.再最终合并的时候,溢写文件个数<=3,那么合并完成之后会再执行一次Combinaer

在这个过程中需要注意的问题:
  1. 当产生溢写的时候,缓冲区最后残留的数据会flush到最后一个溢写文件中
  2.Spill理论上默认是80M,但是要考虑序列化以及最后的冲刷等因素
  3.不能凭借一个MapTask处理的切片大小来衡量MapTask之后的输出数据的多少
  4.每一个切片对应一个MapTask,每一个MapTask对应一个缓冲区
  5.缓冲区本质上是一个字节数组
  6.缓冲区又叫环形缓冲区,好处在于可以重复利用同一块地址的缓冲区
  7.阈值的作用是避免Spill过程产生阻塞
  8.merge过程可能不会发生

Reduce中的shuffle:
  1.ReduceTask启动多个后台线程发起HTTP请求抓取数据----fetch
  
  2.当前的ReduceTask值抓取对应分区的数据
  
  3.RedcueTask从不同的MapTask上抓取了大量的数据,然后对这些数据进行merge(因为每个MapTask中合并的文件中有各个分区的数据)
  
  4.在merge过程中,会对数据进行一次排序,保证当前分区中的数据有效(在这之后会进行一次分组过程)
  
  5.Merge之后数据要进行一次分组(group),将相同的键所对应的值放到一个ArrayList
  
  6.将ArrayList传递到Reducer中,Reducer将ArrayList转化为一个迭代器传到Reduce方法中
  
  在Reduce中需要注意:
  1.fetch的线程数量默认为5个
  2.ReduceTask在启动的时候有一个阈值,这个阈值时表示有几个MapTask
  3.执行完成之后就要启动ReduceTask,阈值默认时0.05(当有5%的mapTask执行完成之后,启动ReduceTack)
  4.merge因子是10(默认十个合一个);

那么Shuffle调优就很重要的,主要有以下的方式:

Reduce阶段:
  1.增加fetch线程的数量
  2.减小reduceTask的阈值—尽量不要动
  3.调大merge因子
Mapper阶段:
  1.调大缓冲区。建议在250—400M
  2.指定combiner减少数据量
  3.压缩数据以减少网络传输过程中的时间消耗(这种方式实际上是在网络和内存之间进行了取舍)