MapReduce之shuffle

来源:互联网 发布:方块乐器软件 编辑:程序博客网 时间:2024/04/30 03:44

   不正之处,欢迎指教。

   MapReduce作为Hadoop的核心之一,是一种经典的大数据计算框架,在MapReduce编程中,涉及到Key和Value的选择。在MapReduce中确保每个Reduce的输入都是按照键排序的。系统按照键排序的过程称之为shuffle,shuffle属于不断被优化和该进代码库的一部分。

1.MapReduce作业运行流程

   在介绍shuffle过程之前,有必要说一下MapReduce中作业运行的大致流程。

          

从上图中可以看出,一个完整的作业流程可以分为下面几个部分:

1.作业启动,由客户端通过控制台启动作业。

2.作业得初始化。

3.作业任务调度。

4.进行map任务。

5.shuffle过程

6.Reduce任务

7.作业完成,将结果写出。

  本文主要介绍map过程,shuffle过程和Reduce过程。说明其中具体的工作流程。下面给出《Hadoop权威指南》一书中对shuffle过程的一张图例。

           

  这幅图把MapReduce大致分为了两个过程,而实际上两边的Map和Reduce到中间的很大一块都是属于shuffle过程,也就是说,shuffle过程在Map和Reduce端都有涉及。

  对于一个集群来说,运行作业的时候,Map和Reduce分别是在不同的节点上执行的,map产生的输出和Reduce工作所需要的输入通常是不在一个节点中的,所以通常Reduce节点需要去Map节点拉取数据,这样造成的结果就是网络内部资源消耗严重,如果集群中运行的作业较多的话,那么对网络资源就是一个很大的挑战,所以我们对shuffle过程的期望就是可以完整的将map产生的输出拉取到Reduce端,减少对网络带宽的利用,减少磁盘IO影响。

2.Map过程

   Map函数读取split分片,一个split对应着一个Map节点,一般来说,读取数据的原则是就近读取,即一个计算节点尽可能的处理本地磁盘上所需要的数据,尽量选择数据所在的DataNode启动任务,如果在本地没有的话尽量选择靠近自己的节点。

   Map函数开始产生输出的时候,并不是直接将 输出写入到磁盘,而是现将产生的输出写入到一个环形缓冲区中,默认的环形缓冲区的大小是100M,默认的环形缓冲区的阈值时0.8,即当环形缓冲区中写入的数据达到80M大小的时候就会产生溢出,此时数据将内存缓冲区写入到磁盘中。在数据写入磁盘的时候,会经历partition,sort和combine的过程。所谓的partition就是对Map输出产生的键值对进行分区的操作,分区的个数也就是接下来Reduce的个数,用户可以根据自己的逻辑自定义partion函数,Hadoop默认的分区实现是Hashpartition根据Key值来确定分区的。

 public int getPartition(K2 key, V2 value,                          int numReduceTasks) {    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;  }
  Sort过程是根据输出的Key值进行排序,对于Text类型就是按照字典序排序,对于IntWritable就是按照大小排序,当然对于自定义的序列化对象,可以自定义排序规则,在写入到磁盘之前,如果程序定义了combine操作,那么此时还会执行一次combine操作,combine操作可以看成一个特殊的Reduce操作,例如在WordCount实例中,combine操作就是将形如<hello,1><hello,1>这样的输出合并为<hello,2>,在数据比较多的情况下,combine操作可以加快执行的效率。

  经过分区,排序,合并操作之后,溢出的数据将会被写入到磁盘上面,这样也就是会形成一系列的分区且排序的小文件,当溢出的次数较多时,最后就会形成若干个split小文件,但是最终map的输出产生的是一个文件,所以还会经历一个merge合并过程。对所有的溢出文件进行合并操作,默认一次可以合并10个文件,在溢出文件进行合并时候,会进行一次排序操作,如果设置了combine操作的话,在合并时候会进行combine过程,最终合并的结果就是产生一个分区且排序的文件。

3.Reduce过程

  Map过程完成之后,现在转移到Reduce端,Map节点产生的输出是在自己的本地磁盘上面的,这一点和Reduce的输出不太一样。现在这些数据将会在那些要运行特定分区任务的Reduce节点上作为输入数据,而且,Reduce任务需要集群中如干个Map节点的输出作为该Reduce的输入。想象一下,现在若干个节点map产生的输出都是一个分区且排序的文件,假如区号为0,1,2,现在假设一个Reduce任务处理的是0号分区的数据,那么这个Reduce就会需要这若干个Map节点输出的0号分区的数据,那么Reduce节点是如何得到这些数据的呢?

  如果Map任务一旦成功执行完成,它们将会利用心跳机制通知其application master,因此,对于一个给定的job,application master就会知道Map节点的输出和hosts之间对应的映射关系。在Reducer端会有一个线程周期性的来询问master进程来获取Map输出的主机信息,知道获得到所有的输出位置。

     

  如果Map的输出较小,会被复制到Reduce任务JVM的内存,否则的话Map的输出就会被复制到磁盘。一旦内存缓冲区达到阈值大小或者达到Map输出阈值,则合并之后写到磁盘中,如果指定了combiner,则在合并期间运行combiner以降低写入到磁盘中的数据量。合并之后就会生成一个文件,当然这个文件也是排好序的文件,这个文件也就是对应的Reduce的输入。到此为止shuffle过程结束。

  在Reduce阶段,对已经排好序的文件调用Reduce函数,将结果写入到输出文件系统,一般为HDFS中。

参考文章

http://wangzzu.github.io/2016/03/02/hadoop-shuffle/    

0 0
原创粉丝点击