map/reduce 过程的认识

 

    map/reduce 过程的认识

 

      最初我一直简单的以为map的工作就是将数据打散,而reduce就是将map打散后的数据合并。虽然之前跑过wordcount的例子,但之前只是对输出reduce最终的结果感兴趣,对控制台打印的日志信息完全不懂。这几天我们团队在探索pagerank,才开始对map/reduce有了深一层的了解。当一个job提交后,后续具体的一系列分配调度工作我现在不清楚。我现在只是了解些map/reduce过程。

 原来map过程和reduce的过程也都包含了多个步骤。

 

         一.  Map 阶段

  作业的inputFormat类规定了对提交的作业的输入文件切分方法。默认是将输入文件按照字节的大小分割成不同的块。  至于这个过程到底是怎么实现的我也不清楚。我现在只是记录下我对map reduce的理解。

 

  输入文件可能会被打散成多个块(block),至于是怎么分成块的,我不清楚。一个块的大小是默认是64MB,也是可以通过参数设置的其大小的。所以若采用默认的,如果初始数据<64MB 时,就只有一个块了。每一个块就是一个Map task的输入。也就是说有多少个块就会有多少个map task map task 的工作是怎么样的呢?

  

 

扫描二维码关注公众号,回复: 1221986 查看本文章

    简单的来说,map task 也有几个步骤:从hdfs上获取block数据à从内存中溢写(spill)文件àmerge溢写文件

           1.   blockmap task怎么联系起来的呢。那些任务都是属于作业提交后的初始化和调度问题了。我还没有明白。第一步就先不说了,只能简单的理解是map task知道它的输入数据(block)在哪里,直接去取就可以了。

 

DataNode节点上的每个map task任务都会有一个内存缓冲区,用来临时存储它的输出结果的,其实也就是减少对磁盘的读写频率。这里面的数据只是key/value对和partition的结果。前者我们都可以理解是什么东西,那后者呢?我们都知道map task的数量不是完全由人为设置的,但reduce task的数目是client设置的,默认是1。这就需要对key值划分区,知道哪些key 是由哪个reduce task处理的。Partitioner就是干这个工作的。默认的方法是使用Hash函数,当然用户也可以通过实现自定义的 Partitioner来控制哪个key被分配给哪个 Reducer结果可能会出现多个key/value对最终交由同一个reduce task去处理。针对这些key/value对就需要合并了,合并是为了减小map最终文件在磁盘上的溢写。至于这个合并到底是在哪个时期进行的,我也不清楚。

 

          2.  当然这个缓冲区也是有大小限制的(默认是100MB)。我们也可以通过某些属性来设置这个具体大小。而如果Map的输出结果很大,缓冲区容纳不了时,必定要适时将缓冲区的数据写在磁盘上(也称为spill过程)。默认为缓冲区的容量达到80%时(当然可以去重新设置了),就将它写入磁盘。如果等到缓冲区满才开始这部分的工作,那在写入磁盘的过程中,map可能还要输出数据,因为那个溢写的过程是由单独的线程控制的。那么是否有可能会出现内存溢出?为了避免这种情况,这就需要前面所说的那个80%的门限值了。而在这个溢写过程也会对这些数据进行sort,默认是使用快速排序对keypartition做排序。这些数据记录本身是以什么格式存储在内存中的我还不清楚,所以也不明白到底是如何个快速排序法。

 

 

          3.  每次spill过程写入磁盘的数据是生成一个单独文件的(通常称为溢写文件),这就又会出现Map真正执行完成后,如果是大数据量结果输出,则会形成很多个溢写文件。那么势必又要将这些个文件合并到一起。这个过程就称为merge 了。至于每次merge的溢写文件数目是可以通过参数设置的,但是我不知道是不是总的merge次数是否也有限定,我现在还不清楚。

 

但是可能又会有疑问了,如果merge只是简单的合并过程,那如果像wordcount例子的情况,假如第一个溢写文件中 单词“hello(key) 出现的次数是4(value),第二个溢写文件中 单词“hello(key) 出现的次数是9(value),假设只有两个溢写文件。那merge后还是会出现相同的key值键对。所以如果之前设置过combiner ,此就会使用combiner将相同的keyvalues合并,形成 hello(key)---[4,9](values) 这个combine过程并不一定要等到merge结束后才执行,而且也并不是一定要执行,用户可以自己设置的。 当这些个步骤都结束后map端的工作 才算结束。最终的这个输出文件也是存储在本地磁盘中的。

 

 

               二. Reduce阶段

Reduce是将map 的输出结果作为它的输入文件。整个reduce过程就又涉及到多个步骤了。Reduce过程并不是要等到所有的map task执行完后才执行。只要有一个map task执行完后,reduce阶段就可以开始了。

       这个过程我只能用粗略图表示了。

 

 

 

             1.  首先就是怎么得到map的输出数据。在实际运行过程中map的运行过程很可能和reduce的运行过程不在同一个节点(datanode)上。那它们之间到底是怎么联系的呢?它是通过HTTP方式请求Jobtracker获取当前有哪些 map task任务已完成,然后从map task所在的TaskTracker远程获取map task的输出文件。但并不是map的整个输出文件,而只是获取由该reduce task处理的那部分数据就可以了。

 

               2.  在这个下载过程中,它也会一边做归并排序,因为不同的Map结果中可能会有相同的key值。为什么是采用归并呢?不懂!如果之前设置了combine,此时也会做这个工作。而对一个reduce来说,它的数据可能是多个map 上的数据,而它的下载过程可以是并行的,不过这个并行的数目是可以设置的,默认是5。也就是说,即使reduce 所需要的数据是从很多个map上的(若是大于设置的并行度),也只能一次并行的从设置的这么多个Map上下载所需数据。

         我想不通的是这样会不会太麻烦了点啊,多浪费网络资源啊。不过,我也不知道它们之间该使用什么样的数据传输会更好。

 

              3.  copy获取到的数据首先也是放入到内存中的,也就是说这里又出现了类似map阶段中的溢写过程了,会产生溢写文件。所以在这里就又有了merge的过程了。使得最终形成一个文件。不过这个文件有可能是在内存中,也有可能是在磁盘上了,默认是在磁盘上的。当最终文件形成后,reduce 函数才开始执行。并将最终的结果写到hdfs上,至于这步是如何写上去的,还不清楚。至此整个reduce 阶段才算结束。在这里还有明白的就是reduce后的结果并不是排序好的,而map 的最终数据是已经排好序的,且已经是分好区的了。

 

     三.  最后还有需要说明的是client可以控制对这些中间结果是否进行压缩以及怎么压缩,使用哪种压缩格式。也不是说一定要这个压缩步骤,若需要写入磁盘的数据量太大,相对来说就可以让CPU帮忙减轻下IO负荷。具体map reduce整个过程中有太多问题还不清楚,还要继续验证。总之就是越发觉得复杂了。

猜你喜欢

转载自linglxia.iteye.com/blog/1396630