大数据系列(四)之 MapReduce过程及shuffle详解

目录

一、什么是MapReduce?

二、怎么理解Hadoop中的MapReduce?

三、MapReduce应用场景

四、MapReduce执行流程

五、shuffle详解

5.1 Map阶段的shuffle

5.2 Reduce阶段的shuffle

六、MapReduce练习WordCount


本篇文章将会介绍 Hadoop 重要的计算框架 MapReduce

本章着重从算法逻辑层面的分而治之思想方面讲解,即 mapshuffle 以及 reduce 三个重要算法组成部分。

在MapReduce计算运行时,Hadoop 2.0 以后,作业都是提交给 YARN 进行管理,在这里就不做更多的介绍了,感兴趣的同学可以去了解一下Hadoop 1.0 时候的作业机制以及发展更新过程。

一、什么是MapReduce?

MapReduce是面向大数据并行处理的计算模型、框架和平台,它隐含了以下三层含义:

1)MapReduce是一个基于集群的高性能并行计算平台(Cluster Infrastructure)。它允许用市场上普通的商用服务器构成一个包含数十、数百至数千个节点的分布和并行计算集群。

2)MapReduce是一个并行计算与运行软件框架(Software Framework)。它提供了一个庞大但设计精良的并行计算软件框架,能自动完成计算任务的并行化处理,自动划分计算数据和计算任务,在集群节点上自动分配和执行任务以及收集计算结果,将数据分布存储、数据通信、容错处理等并行计算涉及到的很多系统底层的复杂细节交由系统负责处理,大大减少了软件开发人员的负担。

3)MapReduce是一个并行程序设计模型与方法(Programming Model & Methodology)。它借助于函数式程序设计语言Lisp的设计思想,提供了一种简便的并行程序设计方法,用Map和Reduce两个函数编程实现基本的并行计算任务,提供了抽象的操作和并行编程接口,以简单方便地完成大规模数据的编程和计算处理 。

Hadoop中的MapReduce 是一个离线批处理计算框架。下面我们都以Hadoop中的MapReduce作为介绍。

二、怎么理解Hadoop中的MapReduce?

理解Hadoop中的MapReduce需要理解Map,Shuffle 和 Reduce三个重要算法,这里先简单介绍一下,后面会详细介绍。

  • Map:每个工作节点将 map 函数应用于本地数据,并将输出写入临时存储。主节点确保仅处理冗余输入数据的一个副本。
  • Shuffle:工作节点根据输出键(由 map 函数生成)重新分配数据,对数据映射排序、分组、拷贝,目的是属于一个键的所有数据都位于同一个工作节点上。
  • Reduce:工作节点现在并行处理每个键的每组输出数据。

Hadoop中的一个MapReduce程序主要分为两个阶段,Map阶段和Reduce阶段,在开发程序的过程中,我们只需要实现Map和Reduce函数,编写数据的处理逻辑,就可以很容易实现一个分布式计算作业。

同时还有几个特性也介绍一下:

1. MapReduce程序有着很好的扩展性,一个MapReduce程序可以运行在成千上万台机器上;

2. MapReduce程序在分布式计算系统中,有着很高的容错性,如果当前机器出现故障,那么计算作业会被调度到其他节点上,不会影响其他任务的运行(这其实是依托于分布式系统的特性);

3. MapReduce程序可以对TB, PB级的数据进行离线处理。

三、MapReduce应用场景

1. 进行数据统计,比如计算大型网站的浏览量 (pv)。

2. 搜素引擎中索引的创建(Google最早使用MapReduce就是对每天爬取的几十亿上百亿的网页创建索引,从而产生的MapReduce框架)。

3. 海量数据中查找出具有某些特征的数据。

4. 复杂数据分析算法的实现(比如聚类,分类算法,推荐算法。这些算法需要大量的训练数据来训练算法模型,一些算法集成工具使用MapReduce使程序跑在分布式系统环境中)。

MapReduce不适合的场景

通过前面的介绍,我们可以发现MapReduce更适合处理海量数据的分布式批量离线处理,所以也就限制了它的使用。比如说:

1. 低延迟实时计算,这种场景通常需要秒级甚至毫秒级返回计算结果。MapReduce式分布式作业的,需要分发执行任务的程序包并且在计算过程中还要在map阶段拆分数据,向Reduce传输数据,所以不能在极短时间内返回计算结果。

2. 流式计算,MapReduce自身框架设计决定了它处理输入的数据必须是静态的数据,比如说它处理存储在HDFS上的数据,HDFS上的数据是不能实时变化的。

四、MapReduce执行流程

MapReduce的执行流程概括的来说是先将输入数据根据一定规则进行拆分(map阶段),再合并计算(reduce阶段)然后输出结果。当然这中间还有重要的Shuffle阶段(后面会详细介绍,这里先介绍map阶段和reduce阶段)。

MapReduce程序处理的是HDFS上的数据,数据在HDFS上存储都是以Block块的形式存储的。MapReduce程序通过InputFormat接口读取Block块上的数据,然后进行逻辑分片(Split )生成<key,value>键值对交给Map阶段处理,(一般情况下,一个Block块对应一个Split。)如下图所示,然后MapTask会处理逻辑分片Split上的数据。

不论是在map阶段还是在reduce阶段,数据的输入输出都是以<key,value>键值对的形式进行输入和输出的。

详细执行流程如下图所示:

MapReduce整个流程分为以下几步:

1. Split 分片在MapTask执行时,其输入数据来源于HDFS的Block。Split分片(最小的计算单元)和Block数据块(最小的存储单元)默认对应关系是一对一。通过InputFormat接口来进行分片和处理数据跨行的问题(默认是TextInputFormat),将数据生成Key-Value键值对的形式,然后输入到map阶段。   

我们举例:假设Map的输入数据都是像“aaa”这样的字符串。同时指定ReduceTask数量为3(我们可以自定义个数)。

2. map 阶段:这里就是我们编写好的map函数了。在经过Mapper运行后,输出是这样一个Key/Value对:Key是“aaa”,Value是1。然后交给Reducer处理。

2.1 Partitioner 分区 :我们知道这个Job有3个ReduceTask,到底“aaa”应该交由哪个Reducer去处理,是需要现在决定的。MapReduce提供了Partitioner接口,默认是HashPartitioner。对Key进行哈希运算后,再以ReduceTask数量取模。接下来需要将数据写入内存缓冲区(也叫环形缓冲区)中。缓冲区的作用就是批量收集Map结果,减少磁盘I/O影响。 

举例中,假设“aaa”经过Partitioner(分区)后返回0,也就是这对输出数据应当由第一个Reducer来处理。

2.2 环形缓冲区溢写:每一次溢写都会在磁盘上生成一个溢写文件,如果Map输入结果很大,就会有多次这样的溢写发生,磁盘上就会有多个溢写文件存在。当MapTask真正完成时,内存缓冲区中的数据将全部溢写到磁盘中形成一个溢写文件。最红磁盘中会至少有这样的一个溢写文件存在(如果Map的输出结果很少(小于100MB),那么当Map执行完成时,只会产生一个溢写文件)。因为最终的文件只有一个,所以需要将这些溢写文件归并(使用归并算法)到一起,这个过程就是Merge。至此,Map端所有工作都已结束。 

每个ReduceTask不断地通过RPC(HTTP协议)从JobTracker(Hadoop2.0有了Yarn之后,是ResourceManager)那里获取MapTask是否完成信息。如果ReduceTask获知某台TaskTraker(Hadoop2.x中为AppMaster)上的MapTask执行完成,那么Shuffle的后半段过程开始启动。简单地说,ReduceTask在执行之前的工作就是不断地拉取当前Job里的每个MapTask的最终结果,然后对不同地方拉取过来的数据不断地进行Merge,最终形成一个文件作为ReduceTask的输入文件。

2.3 分区内排序:从缓冲区写到磁盘的时候,会进行分区并排序,分区指的是某个key应该进入到哪个分区,同一分区中的key会进行排序,如果定义了Combiner的话,也会进行combine操作。

2.4 combiner 合并预聚合:combiner阶段是程序员可以选择的,combiner其实也是一种reduce操作,我们称为预聚合,Combiner是一个本地化的reduce操作,它是map运算的后续操作,主要是在map计算出中间文件前做一个简单的合并重复key值的操作,例如我们对文件里的单词频率做统计,map计算时候如果碰到一个aaa的单词就会记录为1,但是这篇文章里aaa可能会出现n多次,那么map输出文件冗余就会很多,因此在reduce计算前对相同的key做一个合并操作,那么文件会变小,这样就提高了宽带的传输效率,毕竟hadoop计算力宽带资源往往是计算的瓶颈也是最为宝贵的资源,但是combiner操作是有风险的,使用它的原则是combiner的输入不会影响到reduce计算的最终输入。   

例如:如果计算只是求总数,最大值,最小值可以使用combiner,但是做平均值计算使用combiner的话,最终的reduce计算结果就会出错。

3. Reduce 复制copy:每个reducer对应一个ReduceTask,在真正开始reduce之前,先要从mapTask的数据文件中分区中拷贝属于自己的分区数据,在拷贝之后还会伴随着排序(sort)、合并(Merge)。

3.1 Merge 阶段:同Map端的Merge动作,只是数组中存放的是不同Map端复制过来的数据。复制过来 数据会先放到内存缓冲区中,当内存中的数据达到一定阈值时,就会启动内存到磁盘的Merge。与Map端类似,这也是溢写过程,会在磁盘中形成众多的溢写文件,然后将这些溢写文件进行归并。

3.2 Reducer 的输出文件:不断地进行Merge后,最后会生成一个“最终文件”。这个文件可能存放在磁盘,也可能存放在内存中,默认存放在磁盘上。当Reducer的输入文件已定时,整个Shuffle过程才最终结束。

五、shuffle详解

先来一张shuffle的官方流程图,大致了解一下执行情况。

5.1 Map阶段的shuffle

首先理解几个概念:

  • 环形缓冲区:在map任务处理完之后,首先会将这个结果写入到内存缓冲区当中,也就是在内存中会划分出一片区域来存储map任务处理完的数据结果,我们将这个缓冲区称为环形缓冲区。内存缓冲区的大小是有限的,默认是100MB,我们可以通过配置文件来设置其大小。
  • 溢写:当MapTask输出结果有很多时,内存可能会不足,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这个缓冲区。这个从内存往磁盘写数据的过程被称为Spill,中文译为溢写。
  • MapReduce提供了Partitioner接口,默认是HashPartitioner。(其作用是根据Key或Value及Reduce的数量来决定当前这对输出数据最终应该交由哪个ReduceTask处理。)

map阶段的shuffle可以划分为以下四步:

①分区partition

②写入环形内存缓冲区

③执行溢出写

        排序sort--->合并combiner--->生成溢出写文件

④归并merge

map阶段的shuffle是从map输出结果开始的,map任务处理完之后,首先会将这个结果写入到内存缓冲区当中,当写入的数据所占大小占整个环形缓冲区的80%之后,就开始把缓冲区中的数据写入到本地磁盘文件当中(这个过程我们称为溢写),在写出的过程中,map的处理结果仍然回向缓冲区中写入,这个过程可以看作是一个环状,所以称之为环形缓冲区,其实在内存当中就是一个数组。

从环形缓冲区向内存当中写数据之前,在内存当中会调用Partitioner对这个数据进行分区,然后再分区内按照key进行排序,排好序之后再将内存当中的数据写入到文件当中。因为再内存当中已经对分区里面的数据进行了排序,所以写出到文件中的数据在分区内是有序的,如果MapTask产生的结果比较大,就会不断的将缓冲区中的数据溢写到文件当中,根据数据量的大小就会产生多个文件,这些文件当中的数据是分区的,并且分区内是有序的。

当MapTask运行完成之后,会将所有输出的这些小文件合并成一个大的文件,在合并文件的过程中还是会对分区内的文件进行排序,对这个大的文件合并排序结束后,map阶段的shuffle过程就结束了,开始进入Reduce阶段的Shuffle过程。

5.2 Reduce阶段的shuffle

reduce阶段的shuffle可以划分为以下三步:

①复制copy

②归并merge

③reduce

  • reduceTask有少量复制线程,因此能够并行取得map输出。默认线程数为5,但这个默认值可以通过mapreduce.reduce.shuffle.parallelcopies属性进行设置。
  • 【Reducer如何知道自己应该处理哪些数据呢?】 

因为Map端进行partition的时候,实际上就相当于指定了每个Reducer要处理的数据(partition就对应了Reducer),所以Reducer在拷贝数据的时候只需拷贝与自己对应的partition中的数据即可。每个Reducer会处理一个或者多个partition。

  • 【reducer如何知道要从哪台机器上去的map输出呢?】 

map任务完成后,它们会使用心跳机制通知它们的application master、因此对于指定作业,application master知道map输出和主机位置之间的映射关系。reducer中的一个线程定期询问master以便获取map输出主机的位置。知道获得所有输出位置。

当reduce任务开始的时候,ReduceTask就会从所有的MapTask的数据文件中通过HTTP方式请求MapTask所在的NodeManager以获取属于它的输出文件。

当把所有的数据都拷贝过来之后,就会将这些数据合并,Map的输出数据已经是有序的,Merge进行一次合并排序,采取的排序方法跟map阶段不同,因为每个map端传过来的数据是排好序的,因此众多排好序的map输出文件在reduce端进行合并时采用的是归并排序,就是针对键进行归并排序,在合并之后就会将相同的key的数据分到一组,不同的key之间进行排序,最终会形成一个key对应一组值这样一组数据。(一般Reduce是一边copy一边sort,即copy和sort两个阶段是重叠而不是完全分开的。)

一组数据会调用一次我们自己实现的reduce方法进行计算,然后调用OutPutFormat接口(默认是TextOutPutFormat)将结果输出到hdfs当中。

六、MapReduce练习WordCount

这个由于篇幅原因就不贴代码了,WordCount 的练习情况已经上传到了GitHub,地址写在了最后,感谢大家的阅读,希望可以帮助到大家!

GitHub地址:https://github.com/higminteam/bigdata/tree/master/src/main/java/bd

 


关于WordCount练习情况,代码已上传至github,并且为了便于理解,笔者都加了很全面的注释,这里强烈建议大家去动手敲一下,可以更深刻理解MapReduce的Map,Shuffle 和 Reduce 。

 

大数据系列的其他文章:

大数据系列(一)之 ZooKeeper 分布式协调服务

大数据系列(二)之 hdfs 分布式文件系统详解

大数据系列(三)之 Yarn 资源调度框架详解

大数据系列(四)之 MapReduce过程及shuffle详解

大数据系列(五)之 Flume 数据传输

大数据系列(六)之 Spark 分布式计算框架

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值