MapReduce解析

一. MapReduce介绍

现在,我们有一摞牌,我想知道这摞牌中有多少张黑桃。

最直接的方法就是一张一张牌数,最终统计出有多少张是黑桃。这种方式的效率比较低。如果牌的张数很多,例如有10亿张,该方法将完全无用武之地。

这时我们可以使用MapReduce的计算方法

第一步: 把这摞牌分配给所有节点

第二步:让所有节点检查一下自己手中的牌有多少张是黑桃,然后把这个数目汇报给你

第三步: 把所有节点的黑桃数加起来,得到最终结果。

这样分布式计算,每个节点分一分小任务,最终再汇总,就可以快速得到答案了,这就是MapReduce的计算思想.

二. 分布式计算介绍

再举一个例子,我们平时会使用JDBC代码读取数据库数据。

如果我们需要通过JDBC代码去MySQL中获取多达几十G的数据(约4亿行),这时候就会非常慢。

这主要是由于两个方面造成的:

1. 磁盘IO瓶颈

2. 网络IO带宽

这里面其实最耗时的还是网络IO,我们平常两台电脑之间传输一个几十G的文件也需要很长的时间,但用U盘拷贝就相对快速很多,可以看出网络IO比磁盘IO更耗时。

这时我们考虑把计算程序放到MySQL本地执行,而不是远程连接,是不是就可以节省网络IO了? 是的!

如果MySQL的数据量很大的话,我们的数据是由很多个节点存储的(MySQL分库分表),这时候我们就可以把我们的程序代码拷贝到对应的节点上面去执行,但每个数据节点上的代码只能统计当前节点上的数据行数,所以还需要一个汇总程序,这样每个数据节点上的计算结果就可以汇总到一起得到最终结果了。

这就是分布式计算:

(1) 对每个节点数据进行计算

(2) 将每个节点的数据进行汇总得到最终结果。

三.MapReduce原理剖析

MapReduce是一种分布式计算模型,是Google提出来的,主要用于解决海量数据的计算问题

MapReduce是分布式运行的,由两个阶段组成,Map和Reduce

Map阶段是一个独立的程序,在很多节点同时运行,每一个节点处理一部分数据。

Reduce阶段也是一个独立的程序,可以在一个或者多个节点同时运行,每个节点处理一部分数据(在这里可以将Reduce理解为一个单独的聚合程序)

Map就是对数据进行局部汇总,Reduce就是对局部数据进行最终汇总.

如上图,这是一个Hadoop群集,一共5个节点

一个主节点(NameNode),4个从节点(DataNode)

假设我们有一个512MB的文件,这个文件会产生4个block块,假设这4个block块正好分别存储了群集的4个节点上,我们的计算程序会被分发到每一个数据节点,然后开始执行。

在Map阶段,针对每一个block块对应的数据都会产生一个Map任务(这个Map任务其实就是执行这个计算程序的),4个block块意味着会产生4个map任务并行执行,4个Map任务执行完毕以后,就会执行Reduce阶段,在Reduce阶段中会对这4个map任务的输出数据进行汇总,得到最终结果。

MapReduce原理图:

左下角是一个文件,文件最下面是几个block块,这里一共N个block块。文件上面是一些split,注意前面我们说每一个block块会产生一个map任务,其实这是不严谨的,应该是一个Split产生一个Map任务。

block与split之间的关系:

block块是文件的物理切分,不是对文件真正的切分,默认情况是我们可以认为一个split的大小与一个block的大小是一样的,所以一个split产生一个map task,进而推到出一个block对应一个map

最后面有一些Reduce Task任务,Reduce会把结果结束输出到HDFS上,有几个Reduce任务就会产生几个文件,这里共有3个reduce任务,所以会产生3个文件。

注意看map的输入是k1,v1 输出是k2,v2

reduce的输入是k2,v2 输出是k3,v3,都是键值对的形式。

四. MapReduce 之 Map阶段

MapReduce主要分为两大步骤map和reduce,map和reduce在代码层面对应的就是两个类,map对应的是mapper类,reduce对应的是reducer类。

假设我们有一个文件,文件里面有两行内容

hello you

hello me

我们想统计每个单词出现的总次数:

首先是map阶段

第一步:框架会把输入文件(夹)划分为很多InputSplit(即split),默认情况下,每个HDFS的block对应一个Inputsplit。再通过RecordReader类,把每一个InputSplit解析成一个一个的<k1,v1>键值对。默认情况下,每一行数据,都会被解析成一个<k1,v1>。k1是每一行的起始偏移量,v1代表的是那一行内容。所以针对文件中的数据,经过map处理之后的结果是这样的:

<0 , hello you>

<1 , hello me>

注意, map第一次执行会产生<0 , hello you> ,第二次执行会产生<10, hello me> ,并不是执行一次就获取的,因为每一次只会读一行数据。

第二步:框架调用Mapper类中的map(...)函数,map函数的输入是<k1,v1>,输出是<k2,v2>。一个InputSplit对应一个map task。程序员需要自己覆盖Mapper类中的map函数,实现具体的业务逻辑。

因为我们需要统计文件中每个单词出现的总次数,所以需要先把每一行内容中的单词切开,然后记录出现次数为1,这个逻辑就需要我们再map函数中实现了

针对 <0 , hello you>执行这个逻辑之后的结果就是:

<hello , 1>

<you , 1>

针对<10, hello me>执行这个逻辑之后的结果是:

<hello , 1>

<me ,  1>

第三步:框架对map函数输出的<k2,v2>进行分区。不同分区中的<k2,v2>由不同的reduce task处理,默认只有1个分区,所有数据都在一个分区中,最后只产生一个reduce task。

如果有多个分区的话,需要把这些数据根据分区规则分开,本例只有一个分区,分区中的数据为:

<hello , 1>

<you , 1>

<hellp , 1>

<me , 1>

咱们需要按单词计数,其实就是把每个单词出现的次数进行汇总即可,需要进行全局的汇总,不需要进行分区,所以一个reduce任务就能搞定。

第四步:框架对每个分区中的数据,都会按照k2进行排序,分组。分组指的是相同的k2的v2分为一组

先按k2排序:

<hello , 1>

<hello , 1>

<me , 1>

<you , 1>

再按k2进行分组:

<hello,{1,1}>

<me,{1}>

<you,{1}>

第五步:在map阶段,框架可以选择执行Combiner过程

Combiner译为 规约,规则,这是什么意思呢?在刚才的例子中,咱们最终要在reduce端计算单词出现的总次数,其实可以在map端提前执行reduce的计算逻辑,先在map端对单词出现次数进行局部统计,这样可以减少map端到reduce端传输数据的大小,减少网络IO。

Combiner是一个可选项,默认不执行。

第六步:框架会把map task输出<k2,v2>写入linux的磁盘文件中

<hello,{1,1}>

<me,{1}>

<you,{1}>

至此,整个map阶段执行结束。

最后注意一点:

MapReduce是由map和reduce两个阶段组成的,但是reduce阶段步是必须的,也就是说有的mapreduce任务只有map阶段,为什么会有这种任务呢?

reduce主要是做最终聚合的,如果我们这个需求是不需要聚合操作,直接对数据进行过滤处理就行了,那也就意味着数据经过map阶段处理完就结束了,所以如果reduce阶段不存在的话,map结果是可以直接保存到HDFS中的。

五.MapReduce之Reduce阶段

第一步:框架对多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点,这个过程称为 shuffle

针对本例:只有一个分区,所以把数据copy到reduce端后还是老样子

<hello,{1,1}>

<me,{1}>

<you,{1}>

第二步:框架对reduce端接收的相同分区的<k2,v2>数据进行合并,排序,分组。

reduce端接收到的是多个map的输出,对多个map任务中相同分区的数据进行合并,排序,分组

注意:之前在map中已经做了排序,分组,这边也做这些操作,不是重复了吗?

不重复,因为map端是局部的操作,reduce是合并了多个map的排序,可能多个map一合并,就是无序数据了。

本例只有一个分区,所以合并,排序,分组后还是老样子:

<hello,{1,1}>

<me,{1}>

<you,{1}>

第三步:框架调用Reducer类中的reduce方法,reduce方法的输入是<k2,{v2}>,输出是<k3,v3>。一个<k2,{v2}>调用一次reduce函数。程序员需要覆盖reduce函数,实现具体的业务逻辑。

本例,将相同K2的{v2}累加求和,转化为k3,v3写出去:

<hello,2>

<me,1>

<you,1>

第四步:框架将reduce的输出结果保存到HDFS中

hello  2

me  1

you  1

至此,整个reduce阶段结束。

多个文件执行流程:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值