Hadoop-MapReduce工作原理

来源:互联网 发布:淘宝购买流程图片 编辑:程序博客网 时间:2024/05/22 00:49

运行一个MapReduce程序主要设计到四个实体:JobClient、JobTracker、TaskTracker、DFS。其中JobClinet向集群提交任务,JobTracker负责任务调度和跟踪进度,TaskTracker负责执行具体的任务,DFS提交存储支持。

MapReduce的执行流程

1)提交作业。
JobClient首先RPC到JobTracker,提交作业。JobTracker首先检查输出路径是否存在,然后检查输入数据,所有验证通过后,返回给JobClient一个JobId,随后,JobClient将运行Job所需的资源复制到DFS中以JobId为目录名称的共享目录中,JobClient想JobTracker提交运行申请,第一把完成。

2)初始化作业
JobTracker开始初始提交的作业。首先,根据输入计算分片数量,根据分片数量初始化对应数量的map任务,然后根据mapred.reduce.tasks属性初始化对应数量的reduce任务。初始化完成。

3)任务分配
JobTracker分别将map任务和reduce任务下发的TaskTracker,在分配map任务时,回根据输入分片数据的位置进行本地化分配,也就是会尽力包装map任务和对应的输入分片在同一台机器上。每个TaskTracker都有若干个任务槽位,槽位的数量取决于物理机器的计算能力。JobTracker在分配任务时,也会考虑每个JobTracker的负载,即任务操作的占用数量,尽力集群负载更加均衡。

4)执行任务
TaskTracker在执行map或reduce任务时,会创建一个新的JVM,这样可以确保任务的执行情况不影响TaskTracker的正常运行。

5)状态更新
TaskTracker以心跳的方式与JobTracker进行通信,并同时上报自己的节点状态和任务运行状态。

6)任务完成。

失败处理

任务失败

任务失败可以分为:任务抛出异常,子JVM退出和任务挂起。

任务抛出异常:在任务抛出异常时,如果没有被处理JVM会退出,此时,TaskTracker会跟踪的任务异常并记录到日志中。

子JVM退出:TaskTracker会跟踪到子JVM的退出,并标记改任务失败。

任务挂起:对于任务挂起的情况,TaskTracker会跟踪任务进度,如果超过一定时间没有收到进度报告,则会标记该任务失败,并强制杀死子JVM。

当JobTracker跟踪到有任务失败时,会尝试重新分配该任务,重试次数可配置。map任务由mapred.map.max.attemps参数指定,reduce任务由mapred.reduce.max.attemps参数指定。

TaskTracker失败

JobTracker以心跳的方式监视TaskTracker的状态,当TaskTracker因为宕机或者网络延时而在一定的时间(由mapred.tasktracker.expiry.interval参数指定)没有向TaskTracker上报信息时,JobTracker就会任务改TaskTracker已经死亡,并从任务分配队列中移除。对于在该TaskTracker中已经完成的任务,JobTracker正常返回,而未完成的任务全部标记为失败,并向其他的TaskTracker节点分配失败的任务。

JobTracker失败

这是最严重的一种失败,目前Hadoop没有对应的恢复策略,JobTracker天生存在单点故障问题,但这种情况不是经常发生。

Shuffle和排序

map输出时,会对结果按照key进行排序,排序好的数据被shuffle,然后将结果发送给recude,但这个过程相当复杂。
这里写图片描述

下面来揭开shuffle的神秘面纱。

map端

每个map任务都维护着一个缓冲区,这个缓冲区可以理解为是对map任务中间结果的高速缓存,缓冲区大小由io.sort.mb参数指定,默认为100MB。

当缓冲区中的数据超过了指定大小(io.sort.spill.percent,默认0.8)时,一个后台线程会将缓冲区中的数据溢写到磁盘(mapred.local.dir指定),在溢写过程中,map会继续向缓冲区中写入数据,如果此时缓冲区已经被填满,map会阻塞,知道溢写完成。

对map输出进行shuffle基于Map缓冲区溢写,在写入磁盘前,线程会根据job对应的reduce对缓冲区中的数据做分区处理,在每个分区中进行基于key的内排序(in-memory sort),此时,如果job指定了combiner,combiner会基于排序后的map输出运行。

一旦缓冲区被填满,触发溢写,就会创建一个新的溢写文件,所以,当map写入最后一个输入后,可能对应多个溢写文件,在任务完成前,溢写文件将会被合并成一个已分区且已排序的文件。

同时,对于map输出写入磁盘,还可以用mapred.compress.map.output来开启压缩,加快磁盘IO。

总结一下shuffle时发生了什么,
1)根据reduce分区对map输出在内存中进行分区
2)对每个分区中的map输出进行内排序
3)对每个分区中已经排序的map输出应用combiner
4)缓冲区被占满,触发溢写
5)开启compress,加快IO
6)按分区合并溢写文件

Reduce端

单个Map任务的输出被写入本地,reduce需要从多个Map中复制结果,然后合并作为自己的输入。

首先,当有一个map任务完成时,reduce就开始复制数据(并行),如果Map的输出小于Reduce的缓冲区(mapred.job.shuffle.input.buffer.percent)时,数据回驻留在内存,否则会写入磁盘,随着map输出副本越来越多,后台线程会将这些文件合并成一个大的排序文件,最后,reduce把合并好的数据作为reduce输入来执行reduce函数。

0 0
原创粉丝点击