MapReduce源码分析总结Word文件下载.docx

上传人:b****8 文档编号:22878598 上传时间:2023-02-05 格式:DOCX 页数:14 大小:23.31KB
下载 相关 举报
MapReduce源码分析总结Word文件下载.docx_第1页
第1页 / 共14页
MapReduce源码分析总结Word文件下载.docx_第2页
第2页 / 共14页
MapReduce源码分析总结Word文件下载.docx_第3页
第3页 / 共14页
MapReduce源码分析总结Word文件下载.docx_第4页
第4页 / 共14页
MapReduce源码分析总结Word文件下载.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

MapReduce源码分析总结Word文件下载.docx

《MapReduce源码分析总结Word文件下载.docx》由会员分享,可在线阅读,更多相关《MapReduce源码分析总结Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。

MapReduce源码分析总结Word文件下载.docx

Reduce:

k2,list<

v2>

>

k3,v3>

下面通过一个的例子来详细说明这个过程。

WordCount是Hadoop自带的一个例子,目标是统计文本文件中单词的个数。

假设有如下的两个文本文件来运行WorkCount程序:

HelloWorldByeWorld

HelloHadoopGoodByeHadoop

1map数据输入

Hadoop针对文本文件缺省使用LineRecordReader类来实现读取,一行一个key/value对,key取偏移量,value为行内容。

如下是map1的输入数据:

Key1

Value1

如下是map2的输入数据:

2map输出/combine输入

如下是map1的输出结果

Key2

Value2

Hello

1

World

Bye

如下是map2的输出结果

Hadoop

GoodBye

3combine输出

Combiner类实现将相同key的值合并起来,它也是一个Reducer的实现。

如下是combine1的输出

2

如下是combine2的输出

4reduce输出

Reducer类实现将相同key的值合并起来。

如下是reduce的输出

三MapReduce框架结构

1角色

JobTracker

JobTracker是一个master服务,JobTracker负责调度job的每一个子任务task运行于TaskTracker上,并监控它们,如果发现有失败的task就重新运行它。

一般情况应该把JobTracker部署在单独的机器上。

TaskTracker

TaskTracker是运行于多个节点上的slaver服务。

TaskTracker则负责直接执行每一个task。

TaskTracker都需要运行在HDFS的DataNode上,

JobClient

每一个job都会在用户端通过JobClient类将应用程序以及配置参数打包成jar文件存储在HDFS,并把路径提交到JobTracker,然后由JobTracker创建每一个Task(即MapTask和ReduceTask)并将它们分发到各个TaskTracker服务中去执行。

2数据结构

Mapper和Reducer

运行于Hadoop的MapReduce应用程序最基本的组成部分包括一个Mapper和一个Reducer类,以及一个创建JobConf的执行程序,在一些应用中还可以包括一个Combiner类,它实际也是Reducer的实现。

JobInProgress

JobClient提交job后,JobTracker会创建一个JobInProgress来跟踪和调度这个job,并把它添加到job队列里。

JobInProgress会根据提交的jobjar中定义的输入数据集(已分解成FileSplit)创建对应的一批TaskInProgress用于监控和调度MapTask,同时在创建指定数目的TaskInProgress用于监控和调度ReduceTask,缺省为1个ReduceTask。

TaskInProgress

JobTracker启动任务时通过每一个TaskInProgress来launchTask,这时会把Task对象(即MapTask和ReduceTask)序列化写入相应的TaskTracker服务中,TaskTracker收到后会创建对应的TaskInProgress(此TaskInProgress实现非JobTracker中使用的TaskInProgress,作用类似)用于监控和调度该Task。

启动具体的Task进程是通过TaskInProgress管理的TaskRunner对象来运行的。

TaskRunner会自动装载jobjar,并设置好环境变量后启动一个独立的javachild进程来执行Task,即MapTask或者ReduceTask,但它们不一定运行在同一个TaskTracker中。

MapTask和ReduceTask

一个完整的job会自动依次执行Mapper、Combiner(在JobConf指定了Combiner时执行)和Reducer,其中Mapper和Combiner是由MapTask调用执行,Reducer则由ReduceTask调用,Combiner实际也是Reducer接口类的实现。

Mapper会根据jobjar中定义的输入数据集按<

key1,value1>

对读入,处理完成生成临时的<

key2,value2>

对,如果定义了Combiner,MapTask会在Mapper完成调用该Combiner将相同key的值做合并处理,以减少输出结果集。

MapTask的任务全完成即交给ReduceTask进程调用Reducer处理,生成最终结果<

key3,value3>

对。

这个过程在下一部分再详细介绍。

下图描述了Map/Reduce框架中主要组成和它们之间的关系:

3流程

一道MapRedcue作业是通过(job)向master节点的JobTracker提交的,JobTracker接到JobClient的请求后把其加入作业队列中。

JobTracker一直在等待JobClient通过RPC提交作业,而TaskTracker一直通过RPC向JobTracker发送心跳heartbeat询问有没有任务可做,如果有,让其派发任务给它执行。

如果JobTracker的作业队列不为空,则TaskTracker发送的心跳将会获得JobTracker给它派发的任务。

这是一道pull过程。

slave节点的TaskTracker接到任务后在其本地发起Task,执行任务。

以下是简略示意图:

下面详细介绍一下Map/Reduce处理一个工作的流程。

四JobClient

在编写MapReduce程序时通常是上是这样写的:

Configurationconf=newConfiguration();

ar文件包、记录配置信息的xml、记录分割信息的文件。

通知初始化线程

JobTracker中的监听器类EagerTaskInitializationListener负责任务Task的初始化。

JobTracker使用jobAdded(job)加入job到EagerTaskInitializationListener中一个专门管理需要初始化的队列里,即一个list成员变量jobInitQueue里。

resortInitQueue方法根据作业的优先级排序。

然后调用notifyAll()函数,会唤起一个用于初始化job的线程JobInitThread来处理。

JobInitThread收到信号后即取出最靠前的job,即优先级别最高的job,调用TaskTrackerManager的initJob最终调用()执行真正的初始化工作。

()初始化TaskInProgress

任务Task分两种:

MapTask和reduceTask,它们的管理对象都是TaskInProgress。

首先JobInProgress会创建Map的监控对象。

在initTasks()函数里通过调用JobClient的readSplitFile()获得已分解的输入数据的RawSplit列表,然后根据这个列表创建对应数目的Map执行管理对象TaskInProgress。

在这个过程中,还会记录该RawSplit块对应的所有在HDFS里的blocks所在的DataNode节点的host,这个会在RawSplit创建时通过FileSplit的getLocations()函数获取,该函数会调用DistributedFileSystem的getFileCacheHints()获得(这个细节会在HDFS中讲解)。

当然如果是存储在本地文件系统中,即使用LocalFileSystem时当然只有一个location即“localhost”了。

创建这些TaskInProgress对象完毕后,initTasks()方法会通过createCache()方法为这些TaskInProgress对象产生一个未执行任务的Map缓存nonRunningMapCache。

slave端的TaskTracker向master发送心跳时,就可以直接从这个cache中取任务去执行。

其次JobInProgress会创建Reduce的监控对象,这个比较简单,根据JobConf里指定的Reduce数目创建,缺省只创建1个Reduce任务。

监控和调度Reduce任务的是TaskInProgress类,不过构造方法有所不同,TaskInProgress会根据不同参数分别创建具体的MapTask或者ReduceTask。

同样地,initTasks()也会通过createCache()方法产生nonRunningReduceCache成员。

JobInProgress创建完TaskInProgress后,最后构造JobStatus并记录job正在执行中,然后再调用记录job的执行日志。

到这里JobTracker里初始化job的过程全部结束。

2JobTracker调度Job

hadoop默认的调度器是FIFO策略的JobQueueTaskScheduler,它有两个成员变量jobQueueJobInProgressListener与上面说的eagerTaskInitializationListener。

JobQueueJobInProgressListener是JobTracker的另一个监听器类,它包含了一个映射,用来管理和调度所有的JobInProgress。

jobAdded(job)同时会加入job到JobQueueJobInProgressListener中的映射。

JobQueueTaskScheduler最重要的方法是assignTasks,他实现了工作调度。

具体实现:

JobTracker接到TaskTracker的heartbeat()调用后,首先会检查上一个心跳响应是否完成,是没要求启动或重启任务,如果一切正常,则会处理心跳。

首先它会检查TaskTracker端还可以做多少个map和reduce任务,将要派发的任务数是否超出这个数,是否超出集群的任务平均剩余可负载数。

如果都没超出,则为此TaskTracker分配一个MapTask或ReduceTask。

产生Map任务使用JobInProgress的obtainNewMapTask()方法,实质上最后调用了JobInProgress的findNewMapTask()访问nonRunningMapCache。

上面讲解任务初始化时说过,createCache()方法会在网络拓扑结构上挂上需要执行的TaskInProgress。

findNewMapTask()从近到远一层一层地寻找,首先是同一节点,然后在寻找同一机柜上的节点,接着寻找相同数据中心下的节点,直到找了maxLevel层结束。

这样的话,在JobTracker给TaskTracker派发任务的时候,可以迅速找到最近的TaskTracker,让它执行任务。

最终生成一个Task类对象,该对象被封装在一个LanuchTaskAction中,发回给TaskTracker,让它去执行任务。

产生Reduce任务过程类似,使用()方法,实质上最后调用了JobInProgress的findNewReduceTask()访问nonRuningReduceCache。

六TaskTracker

1TaskTracker加载Task到子进程

Task的执行实际是由TaskTracker发起的,TaskTracker会定期(缺省为10秒钟,参见MRConstants类中定义的HEARTBEAT_INTERVAL变量)与JobTracker进行一次通信,报告自己Task的执行状态,接收JobTracker的指令等。

如果发现有自己需要执行的新任务也会在这时启动,即是在TaskTracker调用JobTracker的heartbeat()方法时进行,此调用底层是通过IPC层调用Proxy接口实现。

下面一一简单介绍下每个步骤。

()连接JobTracker

TaskTracker的启动过程会初始化一系列参数和服务,然后尝试连接JobTracker(即必须实现InterTrackerProtocol接口),如果连接断开,则会循环尝试连接JobTracker,并重新初始化所有成员和参数。

()主循环

如果连接JobTracker服务成功,TaskTracker就会调用offerService()函数进入主执行循环中。

这个循环会每隔10秒与JobTracker通讯一次,调用transmitHeartBeat(),获得HeartbeatResponse信息。

然后调用HeartbeatResponse的getActions()函数获得JobTracker传过来的所有指令即一个TaskTrackerAction数组。

再遍历这个数组,如果是一个新任务指令即LaunchTaskAction则调用调用addToTaskQueue加入到待执行队列,否则加入到tasksToCleanup队列,交给一个taskCleanupThread线程来处理,如执行KillJobAction或者KillTaskAction等。

()获取JobTracker指令

在transmitHeartBeat()函数处理中,TaskTracker会创建一个新的TaskTrackerStatus对象记录目前任务的执行状况,检查目前执行的Task数目以及本地磁盘的空间使用情况等,如果可以接收新的Task则设置heartbeat()的askForNewTask参数为true。

然后通过IPC接口调用JobTracker的heartbeat()方法发送过去,heartbeat()返回值TaskTrackerAction数组。

,交给TaskLauncher处理

TaskLauncher是用来处理新任务的线程类,包含了一个待运行任务的队列tasksToLaunch。

会调用TaskTracker的registerTask,创建TaskInProgress对象来调度和监控任务,并把它加入到runningTasks队列中。

同时将这个TaskInProgress加到tasksToLaunch中,并notifyAll()唤醒一个线程运行,该线程从队列tasksToLaunch取出一个待运行任务,调用TaskTracker的startNewTask运行任务。

()启动新任务

调用localizeJob()真正初始化Task并开始执行。

()初始化job目录等

此函数主要任务是初始化工作目录workDir,再将jobjar包从HDFS复制到本地文件系统中,调用()将包解压到工作目录。

然后创建一个RunningJob并调用addTaskToJob()函数将它添加到runningJobs监控队列中。

addTaskToJob方法把一个任务加入到该任务属于的runningJob的tasks列表中。

如果该任务属于的runningJob不存在,先新建,加到runningJobs中。

完成后即调用launchTaskForJob()开始执行Task。

()执行任务

启动Task的工作实际是调用TaskTracker$TaskInProgress的launchTask()函数来执行的。

TaskTracker$()执行任务

执行任务前先调用localizeTask()更新一下jobConf文件并写入到本地目录中。

然后通过调用Task的createRunner()方法创建TaskRunner对象并调用其start()方法最后启动Task独立的java执行子进程。

()创建启动Runner对象

Task有两个实现版本,即MapTask和ReduceTask,它们分别用于创建Map和Reduce任务。

MapTask会创建MapTaskRunner来启动Task子进程,而ReduceTask则创建ReduceTaskRunner来启动。

()启动子进程

TaskRunner负责将一个任务放到一个进程里面来执行。

它会调用run()函数来处理,主要的工作就是初始化启动java子进程的一系列环境变量,包括设定工作目录workDir,设置CLASSPATH环境变量等。

然后装载jobjar包。

JvmManager用于管理该TaskTracker上所有运行的Task子进程。

每一个进程都是由JvmRunner来管理的,它也是位于单独线程中的。

JvmManager的launchJvm方法,根据任务是map还是reduce,生成对应的JvmRunner并放到对应JvmManagerForType的进程容器中进行管理。

JvmManagerForType的reapJvm()

分配一个新的JVM进程。

如果JvmManagerForType槽满,就寻找idle的进程,如果是同Job的直接放进去,否则杀死这个进程,用一个新的进程代替。

如果槽没有满,那么就启动新的子进程。

生成新的进程使用spawnNewJvm方法。

spawnNewJvm使用JvmRunner线程的run方法,run方法用于生成一个新的进程并运行它,具体实现是调用runChild。

2子进程执行MapTask

真实的执行载体,是Child,它包含一个main函数,进程执行,会将相关参数传进来,它会拆解这些参数,通过getTask(jvmId)向父进程索取任务,并且构造出相关的Task实例,然后使用Task的run()启动任务。

run

方法相当简单,配置完系统的TaskReporter后,就根据情况执行runJobCleanupTask,runJobSetupTask,runTaskCleanupTask或执行Mapper。

由于MapReduce现在有两套API,MapTask需要支持这两套API,使得MapTask执行Mapper分为runNewMapper和runOldMapper,我们分析runOldMapper。

runOldMapper

runOldMapper最开始部分是构造Mapper处理的InputSplit,然后就开始创建Mapper的RecordReader,最终得到map的输入。

之后构造Mapper的输出,是通过MapOutputCollector进行的,也分两种情况,如果没有Reducer,那么,用DirectMapOutputCollector,否则,用MapOutputBuffer。

构造完Mapper的输入输出,通过构造配置文件中配置的MapRunnable,就可以执行Mapper了。

目前系统有两个MapRunnable:

MapRunner和MultithreadedMapRunner。

MapRunner是单线程执行器,比较简单,他会使用反射机制生成用户定义的Mapper接口实现类,作为他的一个成员。

MapRunner的run方法

会先创建对应的key,value对象,然后,对InputSplit的每一对<

key,value>

,调用用户实现的Mapper接口实现类的map方法,每处理一个数据对,就要使用OutputCollector收集每次处理kv对后得到的新的kv对,把他们spill到文件或者放到内存,以做进一步的处理,比如排序,combine等。

OutputCollector

OutputCollector的作用是收集每次调用map后得到的新的kv对,宁把他们spill到文件或者放到内存,以做进一步的处理,比如排序,combine等。

MapOutputCollector有两个子类:

MapOutputBuffer和DirectMapOutputCollector。

DirectMapOutputCollector用在不需要Reduce阶段的时候。

如果Mapper后续有reduce任务,系统会使用MapOutputBuffer做为输出,MapOutputBuffer使用了一个缓冲区对map的处理结果进行缓存,放在内存中,又使用几个数组对这个缓冲区进行管理。

在适当的时机,缓冲区中的数据会被spill到硬盘中。

向硬盘中写数据的时机:

(1)当内存缓冲区不能容下一个太大的kv对时。

spillSingleRecord方法。

(2)内存缓冲区已满时。

SpillThread线程。

(3)Mapper的结果都已经collect了,需要对缓冲区做最后的清理。

Flush方法。

spillThread线程:

将缓冲区中的数据spill到硬盘中。

(1)需要spill时调用函数sortAndSpill,按照partition和key做排序。

默认使用的是快速排序QuickSort。

(2)如果没有combiner,则直接输出记录,否则,调用CombinerRunner的combine,先做combin然后输出。

3子进程执行ReduceTask

方法开始和MapTask类似,包括initialize()初始化,runJobCleanupTask(),runJobSetupTask(),runTaskCleanupTask()。

之后进入正式的工作,主要有这么三个步骤:

Copy、Sort、Reduce。

Copy

就是从执行各个Map任务的服务器那里,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 电大

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1