MapReduce

MapReduce概述

分布式并行编程

“摩尔定律”, CPU性能大约每隔18个月翻一番
从2005年开始摩尔定律逐渐失效 ,需要处理的数据量快速增加,人们开始借助于分布式并行编程来提高程序性能
分布式程序运行在大规模计算机集群上,可以并行执行大规模数据处理任务,从而获得海量的计算能力
谷歌公司最先提出了分布式并行编程模型MapReduce, Hadoop MapReduce是它的开源实现,后者比前者使用门槛低很多

在MapReduce出现之前,已经有像MPI这样非常成熟的并行计算框架了,那么为什么Google还需要MapReduce? MapReduce相较于传统的并行计算框架有什么优势?
在这里插入图片描述

MapReduce模型简介

MapReduce该模型编程容易,不需要掌握分布式并行编程细节,也可以很容易把自己的程序运行在分布式系统上,完成海量数据的计算
MapReduce采用“分而治之”策略,一个存储在分布式文件系统中的大规模数据集,会被切分成许多独立的分片(split),这些分片可以被多个Map任务并行处理
MapReduce设计的一个理念就是“计算向数据靠拢”,而不是“数据向计算靠拢”,因为,移动数据需要大量的网络传输开销
MapReduce框架采用了Master/Slave架构,包括一个Master和若干个Slave。Master上运行JobTracker, Slave上运行TaskTracker
Hadoop框架是用Java实现的,但是, MapReduce应用程序则不一定要用Java来写

Map和Reduce函数

在这里插入图片描述

MapReduce的体系结构

MapReduce体系结构主要由四个部分组成,分别是: Client、 JobTracker、TaskTracker以及Task
在这里插入图片描述

  1. client
    用户编写的MapReduce程序通过Client提交到JobTracker端
    用户可通过Client提供的一些接口查看作业运行状态

  2. JobTracker
    JobTracker负责资源监控和作业调度
    JobTracker 监控所有TaskTracker与Job的健康状况,一旦发现失败,就将相应的任务转移到其他节点
    JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器(TaskScheduler),而调度器会在资源出现空闲时,选择合适的任务去使用这些资源

  3. TaskTracker
    TaskTracker 会周期性地通过“心跳”将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时接收JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等)
    TaskTracker 使用**“slot”**等量划分本节点上的资源量(CPU、内存等)。一个Task 获取到一个slot 后才有机会运行,而Hadoop调度器的作用就是将各个TaskTracker上的空闲slot分配给Task使用。 slot 分为Map slot 和Reduce slot 两种,分别供MapTask 和Reduce Task 使用(两者井水不犯河水)

  4. Task
    Task 分为Map Task 和Reduce Task 两种,均由TaskTracker 启动。

MapReduce工作流程

工作流程概述

在这里插入图片描述
大规模数据集的处理包括分布式存储和分布式计算两个核心环节。谷歌公司用分布式文件系统GFS实现分布式数据存储,用MapReduce实现分布式计算;而Hadoop则使用分布式文件系统HDFS实现分布式数据存储,用Hadoop MapReduce实现分布式计算。MapReduce 的输人和输出都需要借助于分布式文件系统进行存储,这些文件被分布存储到集群中的多个节点上。
MapReduce的核心思想可以用“分而治之”来描述,如图所示,也就是把一个大的数据集拆分成多个小数据块在多台机器上并行处理,也就是说,一个大的MapReduce作业,首先会被拆分成许多个Map任务在多台机器上并行执行,每个Map任务通常运行在数据存储的节点上,这样,计算和数据就可以放在一起运行,不需要额外的数据传输开销。当Map任务结束后,会生成以**<key,value>形式表示的许多中间结果**。然后,这些中间结果会被分发到多个Reduce任务在多台机器上并行执行,具有相同key<key,value>会被发送到同一个Reduce任务那里,Reduce 任务会对中间结果进行汇总计算得到最后结果,并输出到分布式文件系统中。

需要指出的是,不同的Map任务之间不会进行通信,不同的Reduce任务之间也不会发生任何信息交换;用户不能显式地从一台机器向另一台机器发送消息,所有的数据交换都是通过MapReduce框架自身去实现的。
在MapReduce的整个执行过程中,Map任务的输入文件、Reduce 任务的处理结果都是保存在分布式文件系统中的,而Map任务处理得到的中间结果则保存在本地存储中(如磁盘)。另外,只有当Map处理全部结束后,Reduce过程才能开始;只有Map需要考虑数据局部性,实现“计算向数据靠拢”,而Reduce则无需考虑数据局部性。

MapReduce各个执行阶段

在这里插入图片描述
( 1) MapReduce框架使用InputFormat 模块做Map前的预处理,比如验证输入的格式是否符合输入定义;然后,将输入文件切分为逻辑上的多个InputSplit, InputSplit 是MapReduce对文件进行处理和运算的输入单位,只是一个逻辑概念,每个InputSplit并没有对文件进行实际切割,只是记录了要处理的数据的位置和长度。

(2)因为InputSplit 是逻辑切分而非物理切分,所以还需要通过RecordReader ( RR)根据InputSplit中的信息来处理InputSplit中的具体记录,加载数据并转换为适合Map任务读取的键值对,输人给Map任务。

(3) Map任务会根据用户自定义的映射规则,输出一系列的<key,value>作为中间结果。

(4 )为了让Reduce可以并行处理Map的结果,需要对Map的输出进行一定的分区( Portition )、排序( Sort)、合并( Combine)、归并( Merge )等操作,得到<key,value lists>形式的中间结果,再交给对应的Reduce 进行处理,这个过程称为Shuffle。 从无序的<key,value>到有序的<key,value-list>,这个过程用Shuffle (洗牌)来称呼是非常形象的。

(5) Reduce以一系列<key,value-list>中间结果作为输入,执行用户定义的逻辑,输出结果给OutputFormat模块。

(6) OutputFormat模块会验证输出目录是否已经存在以及输出结果类型是否符合配置文件中的配置类型,如果都满足,就输出Reduce的结果到分布式文件系统。

关于split(分片)

HDFS 以固定大小的block 为基本单位存储数据,而对于MapReduce 而言,其处理单位是split。 split 是一个逻辑概念,它只包含一些元数据信息,比如数据起始位置、数据长度、数据所在节点等。它的划分方法完全由用户自己决定。
在这里插入图片描述
Hadoop为每个split创建一个Map任务, split 的多少决定了Map任务的数目。大多数情况下,理想的分片大小是一个HDFS块

最优的Reduce任务个数取决于集群中可用的reduce任务槽**(slot)**的数目,通常设置比reduce任务槽数目稍微小一些的Reduce任务个数(这样可以预留一些系统资源处理可能发生的错误)

Shuffle过程详解

所谓 Shuffle, 是指对Map输出结果进行分区、 排序、合并等处理并交给 Reduce的过程。因此,Shuffle 过程分为Map端的操作和Reduce端的操作

在这里插入图片描述

在Map端的Shuffle过程

(1)输入数据和执行Map任务
Map任务的输人数据一般保存在分布式文件系统 (如GFS或HDFS )的文件块中,这些文件块的格式是任意的,可以是文档,也可以是二进制格式的。Map任务接受<key,value>作为输入后,按一定的映射规则转换成一批<key,value>进行输出。

(2)写入缓存
每个Map任务都会被分配一个缓存,Map的输出结果不是立即写人磁盘,而是首先写人缓存。在缓存中积累一定数量的Map输出结果以后,再一次性批量写人磁盘,这样可以大大减少对磁盘I/O的影响。因为,磁盘包含机械部件,它是通过磁头移动和盘片的转动来寻址定位数据的,每次寻址的开销很大,如果每个Map输出结果都直接写人磁盘,会引人很多次寻址开销,而一次性批量写入,就只需要一次寻址、连续写入,大大降低了开销。需要注意的是,在写入缓存之前,key与value值都会被序列化成字节数组。

(3)溢写(分区、排序和合并)
提供给MapReduce的缓存的容量是有限的,默认大小是100 MB。随着Map任务的执行,缓存中Map结果的数量会不断增加,很快就会占满整个缓存。这时,就必须启动溢写( Spill )操作,把缓存中的内容一次性写人磁盘,并清空缓存。溢写的过程通常是由另外一个单独的后台线程来完成的,不会影响Map结果往缓存写入,但是为了保证Map结果能够不停地持续写入缓存,不受溢写过程的影响,就必须让缓存中- -直有可用的空间,不能等到全部占满才启动溢写过程,所以一般会设置一个溢写比例,如0.8,也就是说,当100 MB大小的缓存被填满80 MB数据时,就启动溢写过程,把已经写人的80 MB数据写人磁盘,剩余20 MB空间供Map结果继续写入。
但是,在溢写到磁盘之前,缓存中的数据首先会被分区( Partition )。缓存中的数据是<key,value>形式的键值对,这些键值对最终需要交给不同的Reduce任务进行并行处理。MapReduce通过Partitioner接口对这些键值对进行分区,默认采用的分区方式是采用Hash函数对key进行哈希后再用Reduce任务的数量进行取模,可以表示成hash(key) mod R,其中R表示Reduce任务的数量,这样,就可以把Map输出结果均匀地分配给这R个Reduce 任务去并行处理了。当然,MapReduce也允许用户通过重载Partitioner接口来自定义分区方式。对于每个分区内的所有键值对,后台线程会根据key 对它们进行内存排序(Sort),排序是MapReduce的默认操作。排序结束后,还包含-个可选的合并( Combine )操作。如果用户事先没有定义Combiner函数,就不用进行合并操作。如果用户事先定义了Combiner函数,则这个时候会执行合并操作,从而减少需要溢写到磁盘的数据量。
所谓“合并”,是指将那些具有相同key的<key,value>的value加起来。比如,有两个键值对<“xmu" 1>和<“xmu" 1>,经过合并操作以后就可以得到一个键值对<“xmu”2>,减少了键值对的数量。这里需要注意,Map端的这种合并操作,其实和Reduce的功能相似,但是由于这个操作发生在Map端,所以我们只能称之为“合并”,从而有别于Reduce。 不过,并非所有场合都可以使用Combiner,因为Combiner的输出是Reduce任务的输入,Combiner绝不能改变Reduce任务最终的计算结果,一般而言,累加、最大值等场景可以使用合并操作。
经过分区、排序以及可能发生的合并操作之后,这些缓存中的键值对就可以被写入磁盘,并清空缓存。每次溢写操作都会在磁盘中生成一个新的溢写文件,写入溢写文件中的所有键值对都是经过分区和排序的。

(4)文件归并
每次溢写操作都会在磁盘中生成一个新的溢写文件,随着MapReduce任务的进行,磁盘中的溢写文件数量会越来越多。当然,如果Map输出结果很少,磁盘上只会存在一个溢写文件,但是通常都会存在多个溢写文件。最终,在Map任务全部结束之前,系统会对所有溢写文件中的数据进行归并(Merge),生成一个大的溢写文件,这个大的溢写文件中的所有键值对也是经过分区和排序的。
所谓“归并”,是指对于具有相同key的键值对会被归并成一个新的键值对。具体而言,对于若干个具有相同key 的键值对<kj,V>, <k,v2> … <k,n> 会被归并成一个新的键值对<k,<v1,v2,v3…>>。
另外,进行文件归并时,如果磁盘中已经生成的溢写文件的数量超过参数min.num.spills.for.combine的值时(默认值是3,用户可以修改这个值),那么,就可以再次运行Combiner,对数据进行合并操作,从而减少写人磁盘的数据量。但是,如果磁盘中只有一两个溢写文件时,执行合并操作就会“得不偿失”,因为执行合并操作本身也需要代价,因此不会运行Combiner。

经过上述4个步骤以后,Map端的Shuffle 过程全部完成,最终生成的一个大文件会被存放在本地磁盘上。这个大文件中的数据是被分区的,不同的分区会被发送到不同的Reduce任务进行并行处理。JobTracker会一直监测Map任务的执行,当监测到一个Map任务完成后,就会立即通知相关的Reduce任务来“领取”数据,然后开始Reduce端的Shuffle 过程。

Reduce端的Shuffle过程

Reduce任务通过RPC向JobTracker询问Map任务是否已经完成,若完成,则领取数据
Reduce领取数据先放入缓存,来自不同Map机器,先归并,再合并,写入磁盘
多个溢写文件归并成一个或多个大文件,文件中的键值对是排序的
当数据很少时,不需要溢写到磁盘,直接在缓存中归并,然后输出给Reduce
在这里插入图片描述

在这里插入图片描述

实例分析:WordCount

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

取个名字真难啊啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值