4.MapReduce基本原理

mapreduce工作原理

(1).客户端提交一个mr的jar包给JobClient(提交方式:hadoopjar ...)

(2).JobClient通过RPC和RM进行通信,返回一个存放jar包的地址(HDFS)和jobId

(3).client将jar包写入到HDFS当中(path = hdfs上的地址+ jobId)----------默认写10份,当程序结束后删除

(4).开始提交任务(任务的描述信息,不是jar,包括jobid,jar存放的位置,配置信息等等)

(5).MR进行初始化任务(保存作业的描述信息……)--将任务放置在调度器中,调度器是个队列--------先进先出调度器(默认)也可以是公平调度器…

(6).读取HDFS上的要处理的文件,开始计算输入分片,每一个分片对应一个MapperTask

(7).NM通过心跳机制领取任务(任务的描述信息)

(8).下载所需的jar,配置文件等

(9).NodeManager启动一个javachild子进程,用来执行具体的任务(MapperTask或ReducerTask)

(10).将结果写入到HDFS当中




mapreduce的执行流程



shuffle过程详解

在Hadoop这样的集群环境中,大部分maptask与reduce task的执行是在不同的节点上。很多情况下Reduce执行时需要跨节点去拉取其它节点上的maptask结果。如果集群正在运行的job有很多,那么task的正常执行对集群内部的网络资源消耗会很严重。这种网络消耗是正常的,我们不能限制,能做的就是最大化地减少不必要的消耗。还有在节点内,相比于内存,磁盘IO对job完成时间的影响也是可观的。从基本要求,我们对Shuffle过程的期望可以有: 

1.完整地从map task端拉取数据到reduce端。

2.在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗。

3.减少磁盘IOtask执行的影响。

4.减少拉取数据的量及尽量使用内存而不是磁盘


执行顺序:

Block-----split------map读取文件,将内容写入环形缓冲区,达到0.8-----》通过分区规则进行分区-------》对每个分区中的数据进行内排序---》如果有combiner,执行combiner



shuffle具体描述:

先将数据写入到环形缓冲区,当环形缓冲区达到80%,进行写磁盘,在写磁盘之前,线程首先根据数据最终要传送到reducer把数据划分成相应的分区(如果没有添加分区、系统按照默认的分区规则进行,否则按照自己编写的partition进行),在每个分区中,后台线程按键进行内排序,如果有一个combiner,它会在排序后的输出上运行。


什么时候运行Combiner?---------------------注意:combiner到底如何运行,还没具体了解,这是借鉴来的。

1、当job设置了Combiner,并且spill的个数到min.num.spill.for.combine(默认是3)的时候,那么combiner就会Merge之前执行; 

2、但是有的情况下,Merge开始执行,但spill文件的个数没有达到需求,这个时候Combiner可能会在Merge之后执行; 

3、Combiner也有可能不运行,Combiner会考虑当时集群的一个负载情况。如果集群负载量很大,会尽量提早执行完map,空出资源,所以,就不会去执行。


mapreduce详解


1. map task执行时,它的输入数据来源于HDFSblockmap task只读取splitSplitblock的对应关系可能是多对一,默认是一对一

 

2.每个maptask都有一个内存缓冲区,存储着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘,当整个maptask结束后再对磁盘中这个map task产生的所有临时文件做合并,生成最终的正式输出文件,然后等待reduce task来拉数据。

 

MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对输出数据最终应该交由哪个reducetask处理。默认对key hash后再以reducetask数量取模。默认的取模方式只是为了平均reduce的处理能力,如果用户自己对Partitioner有需求,可以订制并设置到job上。

 

经过Partitioner后返回数值,也就是这对值应当交由第个reducer来处理。接下来,需要将数据写入内存缓冲区中,缓冲区的作用是批量收集map结果,减少磁盘IO的影响。我们的key/value对以及Partition的结果都会被写入缓冲区。当然写入之前,key与value值都会被序列化成字节数组。 

 

3.内存缓冲区默认是100MB。需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill,中文可译为溢写,溢写是由单独线程来完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止map的结果输出,所以整个缓冲区有个溢写的比例spill.percent。这个比例默认是0.8,也就是当缓冲区的数据已经达到阈值(buffersize * spill percent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这80MB的内存,执行溢写过程。Maptask的输出结果还可以往剩下的20MB内存中写,互不影响。 

 

当溢写线程启动后,需要对80MB空间内的key做排序(Sort)。排序是MapReduce默认的行为,这里排序也是对序列化的字节的排序。 

 

在这里因为map task的输出是需要发送到不同的reduce端去,而内存缓冲区没有对将发送到相同reduce端的数据做合并,那么这种合并应该是体现是磁盘文件中的。从官方图上也可以看到写到磁盘中的溢写文件是对不同的reduce端的数值做过合并。所以溢写过程一个很重要的细节在于,如果有很多个key/value对需要发送到某个reduce端去,那么需要将这些key/value值拼接到一块,减少与partition相关的索引记录。 

 

MapReduce中将Combiner等同于Reducer如果client设置过Combiner,那么现在就是使用Combiner的时候了。将有相同keykey/value对的value加起来,减少溢写到磁盘的数据量。Combiner会优化MapReduce的中间结果,所以它在整个模型中会多次使用。那哪些场景才能使用Combiner呢?从这里分析,Combiner的输出是Reducer的输入,Combiner绝不能改变最终的计算结果。所以从我的想法来看,Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大值等。

 

4.每次溢写会在磁盘上生成一个溢写文件,如果map的输出结果很大,有多次这样的溢写发生,磁盘上相应的就会有多个溢写文件存在。因为最终的文件只有一个,所以需要将这些溢写文件归并到一起,这个过程就叫做Merge。如前面的例子,“aaa”从某个maptask读取过来时值是5,从另外一个map读取时值是8,因为它们有相同的key,所以得merge成group。什么是group。对于“aaa”就是像这样的:{“aaa”, [5, 8, 2,…]},数组中的值就是从不同溢写文件中读取出来的,然后再把这些值加起来。请注意,因为merge是将多个溢写文件合并到一个文件,所以可能也有相同的key存在,在这个过程中如果client设置过Combiner,也会使用Combiner来合并相同的key。

 

注意:Map输出总是写到本地磁盘,但是Reduce出不是,一般是写到HDFS


5. Copy过程,简单地拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求maptask所在的TaskTracker获取map task的输出文件。Reduce务的输入数据分布在集群内的多个Map任务的输出中,Map任务可能会在不同的时间内完成,只要有其中一个Map任务完成,Reduce任务就开始拷贝他的输出。Reduce任务拥有多个拷贝线程,可以并行的获取Map输出。可以通过设定mapred.reduce.parallel.copies来改变线程数。因为map task早已结束,这些文件就归TaskTracker管理在本地磁盘中。


6. Merge阶段。这里的mergemap端的merge动作,只是数组中存放的是不同mapcopy来的数值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活,它基于JVMheap size设置,因为Shuffle阶段Reducer不运行,所以应该把绝大部分的内存都给Shuffle用。这里需要强调的是,merge有三种形式:1)内存到内存  2)内存到磁盘  3)磁盘到磁盘。默认情况下第一种形式不启用,让人比较困惑,是吧。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。与map端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge方式生成最终的那个文件。

7. Reducer的输入文件。不断地merge后,最后会生成一个“最终文件”。为什么加引号?因为这个文件可能存在于磁盘上,也可能存在于内存中。对我们来说,当然希望它存放于内存中,直接作为Reducer的输入,但默认情况下,这个文件是存放于磁盘中的。至于怎样才能让这个文件出现在内存中,待定。当Reducer的输入文件已定,整个Shuffle才最终结束。然后就是Reducer执行,把结果放到HDFS上。 

对写入到磁盘的数据进行压缩(这种压缩同Combiner的压缩不一样)通常是一个很好的方法,因为这样做使得数据写入磁盘的速度更快,节省磁盘空间,并减少需要传送到Reducer的数据量。默认输出是不被压缩的,但可以很简单的设置mapred.compress.map.outputtrue启用该功能。压缩所使用的库由mapred.map.output.compression.codec来设定

 

map和reduce执行之间的管理

任务总体调度由resourcemanager 管理,map和reduce的具体执行交给nodemanager,nodemanager会启动yarnchild线程来执行具体任务,期间由mrappmaster管理map任务和reduce之间的协调


Reduce是怎么知道从哪些TaskTrackers中获取Map的输出呢?

hadoop1.0

Map任务完成之后,会通知他们的父TaskTracker,告知状态更新,然后TaskTracker再转告JobTracker,这些通知信息是通过心跳通信机制传输的,因此针对以一个特定的作业,jobtracker知道Map输出与tasktrackers的映射关系。Reducer中有一个线程会间歇的向JobTracker询问Map输出的地址,直到把所有的数据都取到。在Reducer取走了Map输出之后,TaskTracker不会立即删除这些数据,因为Reducer可能会失败,他们会在整个作业完成之后,JobTracker告知他们要删除的时候才去删除。

hadoop2.0

Map任务完成之后,会通知他们的管理者mrappmaster,告知状态更新,负责运行reduce的yarnchild通过心跳通信机制传输的获取任务,因此针对以一个特定的作业,reduce就知道Map输出与nodemanager的映射关系。Reducer中有一个线程会间歇的向mrappmaster询问Map输出的地址,直到把所有的数据都取到。在Reducer取走了Map输出之后,nodemanager不会立即删除这些数据,因为Reducer可能会失败,他们会在整个作业完成之后,mrappmaster告知他们要删除的时候才去删除。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值