`

MapReduce流程分析

阅读更多

原文:http://blog.csdn.net/jackydai987/article/details/6227365

 

MapReduce流程分析

接触Hadoop已经1年了,一直没时间好好学习下。这几天打算好好研究下Hadoop.本来是想打算改写下TextInputFormat。看了源码后,反而更迷糊了。所以干脆连MapReduce的整个流程写下来。也当为这几天的学习作个总结。

先来一个我们常写的main函数。

Configuration conf = new Configuration();

              String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

              if (otherArgs.length != 2){

                     System.exit(2);

              }

              Job job = new Job(conf, "wordcount");

             

              job.setJarByClass(mywordcount.class);

             

              job.setInputFormatClass(TextInputFormat.class);

             

              job.setOutputKeyClass(Text.class);

              job.setOutputValueClass(IntWritable.class);

             

              job.setMapperClass(wordcountMapper.class);

              job.setReducerClass(wordcountReduce.class);

              job.setCombinerClass(wordcountReduce.class);

             

              FileInputFormat.setInputPaths(job, new Path(otherArgs[0]));

              FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));

             

              job.waitForCompletion(true);

上述程序我就不分析。直接来分析下运行流程。

master节点的NameNode, SecondedNameNode,JobTrackerslaves节点的DataNode, TaskTracker都已经启动后,JobTracker一直在等待JobClient通过RPC提交作业,TaskTracker一直通过RPC JobTracker发送心跳heartbeat询问有没有任务可做。

而主程序中通过job.waitForCompletion(true)函数通过调用JobClient.runJob()函数将MapReduce作业交与JobTrack进行执行。

1JobClient.runJob()

runjob会根据用户的设置(job.setInputFormatClass())来将需要输入的数据划分成小的数据集,同时返回划分后split想的相应信息(这里的split路径信息我估计应该是hdfs里的路径和偏移,因为我们要处理的数据早应该上传到了hdfs系统)。同时根据split设置MapTask的个数。获取了上面信息后,就将运行任务所需要的全部数据、信息全部上传至HDFS。上传的内容主要包括三个包: job.jar, job.splitjob.xml

job.xml: 作业配置,例如Mapper, Combiner, Reducer的类型,输入输出格式的类型等。
job.jar: jar
,里面包含了执行此任务需要的各种类,比如 Mapper,Reducer等实现。

job.split:
文件分块的相关信息,比如有数据分多少个块,块的大小(默认64m)等。

进行完上述工作后,本地的工作就完成了,函数jobSubmitClient.submitJob(jobId)调用真正的JobTracker执行Task

2:JobTracker.submitJob()

JobTracker接收到新的job请求(即submitJob()函数被调用)后,会创建一个JobInProgress对象并通过它来管理和调度任务。JobInProgress在创建的时候会初始化一系列与任务有关的参数,调用FileSystem,把在JobClient端上传的所有任务文件下载到本地的文件系统中的临时目录里。这其中包括上传的*.jar文件包、记录配置信息的xml、记录分割信息的文件。

JobTracker的构造函数中,会生成一个taskScheduler成员变量,来进行Job的调度, 默认为JobQueueTaskScheduler,也即按照FIFO的方式调度任务。而在offerService函数中也为JobTracker(也即taskSchedulertaskTrackerManager)注册了两个Listener

  • JobQueueJobInProgressListener jobQueueJobInProgressListener用于监控job的运行状态
  • EagerTaskInitializationListener eagerTaskInitializationListener用于对Job进行初始化

EagerTaskInitializationListenerjobAdded函数就是向jobInitQueue中添加一个JobInProgress对象,于是自然触发了此Job的初始化操作。由JobInProgressinitTasks函数完成:

3initTasks()

任务Task分两种: MapTask reduceTask,它们的管理对象都是TaskInProgress

initTasks函数,会通过JobClientreadSplitFile()获得已分解的输入数据的RawSplit列表,然后通过这个列表创建相应的TaskInProgress(MapTask)同时还会读取相应数据块所在DataNode的主机名(通过FileSplitgetLocations()函数获取)。创建完TaskInProgress后,就会调用createCache()方法为这些TaskInProgress对象产生一个未执行任务的Map缓存nonRunningMapCache。当TaskTrackerJobTrack中发送心跳,请求任务时,就会去直接去这个缓存中取任务。

JobInProgress也会创建Reduce的监控对象- TaskInProgress,而这个的数量就是根据用户在程序里的设置,默认的是一个。同样地,initTasks()也会通过createCache()方法产生nonRunningReduceCache成员。JobInProgress再接着进行清理工作。最后再记录一下Job的执行日志。

至此Job的初始化就全部完成。

4TaskTracker

TaskTracker从启动后,就每隔一定的时间向JobTracker发送一次心跳(默认10s,发送的内容包括自己的当前状态,当满足一定状态时就可以向JobTracker申请新的任务。如Map Task Reduce Task都还有运行的能力)通过transmitHeartBeat()发送心跳后再接受JobTracker返回的HeartbeatResponse。然后调用HeartbeatResponsegetActions()函数获得JobTracker传过来的所有指令即一个TaskTrackerAction数组。再遍历这个数组,就可以知道需要完成的事情。(这些事情可能是LaunchTaskAction 执行新任务、 KillTaskAction 结束一个任务)如果有分配好的任务将其加入队列,调用addToTaskQueue,如果是map task则放入mapLancher(类型为TaskLauncher),如果是reduce task则放入reduceLancher(类型为TaskLauncher)

5 JobTrackerheartbeat()

 JobTracker是通过heartbeat()函数来接受TaskTracker的心跳,如果TaskTracker是请求任务的指令。Heartbeat()函数就会调用默认的任务调度器(JobQueueTaskScheduler)来分配任务。先计算MapReduce的剩余工作量,再计算每个TaskTracker应有的工作量。如果TaskTracker上运行的map task数目小于平均的工作量,则向其分配map  task。分配完Map Task后再分配Reduce task.而这里有一个函数findNewMapTask()就是从nonRunningMapCachenonRunningReduceCache中查找出map  taskTaskInProgressReduce task. TaskInProgress再返回给TaskTracker

findNewMapTask()从近到远一层一层地寻找,首先是同一节点,然后在寻找同一机柜上的节点,接着寻找相同数据中心下的节点,直到找了maxLevel层结束。这样的话,在JobTrackerTaskTracker派发任务的时候,可以迅速找到最近的TaskTracker,让它执行任务。(通过寻找本任务split所在的DataNode,然后判断发送心跳的TaskTracker和本任务split所在的DataNode是不是同一主机。如果是则分配这个MapTask给发送心跳的Tracker,如果不是者返回null不进行分配。)

再调用localizeJob()进行真正的初始化(TaskTracker上的Task)。而localizeJob又调用TaskLauncher

6TaskLauncher

TaskLauncher是一个线程就是从上面的队列中取出TaskInProgress然后调用startNewTask(TaskInProgress tip)来启动一个task

这里又会再次将Task有关的数据包、信息包从HDFS拷贝回本地文件系统包括:job.splitjob.xml以及job.jar,当所有的资源拷贝回来后,就调用launchTaskForJob()开始执行Task.

launchTaskForJob函数又调用launchTask()

7launchTask()

 launchTask()函数首先通过createRunner()函数是创建MapTaskRunner来启动子进程和创建ReduceTaskRunner来启动子进程。TaskRunner负责将一个任务放到一个进程里面来执行。它会调用run()函数来处理。run()函数会初始化一系列环境变量等。最后生成一个新进程并运行即runChild

8 Child进程

真正的map taskreduce task都是在Child进程中运行的。Child进程会运行Task.

9MapTask

如果是MapTaskMapTask.run()首先向TaskTracker汇报情况,再设置Mapper的输出格式。接着读取input split,按照其中的信息,生成RecordReader来读取数据。这其中会生成一个MapRunnable

,而MapRunnable要完成的任务就时通过RecordReadernext函数读取循环从split中读取<k,v>交给map函数进行处理,然后使用OutputCollector收集每次处理<k,v>对后得到的新的<k,v>.

10:OutputCollector

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

MapOutputCollector 有两个子类:MapOutputBufferDirectMapOutputCollector DirectMapOutputCollector用在不需要Reduce阶段的时候。如果Mapper后续有reduce任务,系统会使用MapOutputBuffer做为输出, MapOutputBuffer使用了一个缓冲区对map的处理结果进行缓存,放在内存中. 在适当的时机,缓冲区中的数据会被spill到硬盘中。spillThread线程实现将缓冲区的数据写入硬盘。

向硬盘中写数据的时机:

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

2)内存缓冲区已满时。SpillThread线程。

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

11ReduceTask

ReduceTask .run()函数同样先进行一系列的初始化工作。之后进入正式的工作,主要有这么三个步骤:CopySortReduce

11.1:copy

copy就是从执行各个Map任务的服务器那里,搜罗map的输出文件。

拷贝的任务的是由ReduceTask.ReduceCopier 类来负责。ReduceCopier先向父TaskTracker询问此作业个Map任务的完成状况,获取到map服务器的相关信息后由线程MapOutputCopier做具体的拷贝工作。在拷贝过来的同时也会做一些归并排序以减轻后面sort的负担。

11.2 Sort

排序工作,就相当于上述排序工作的一个延续。它会在所有的文件都拷贝完毕后进行。使用工具类Merger归并所有的文件。经过这一个流程,一个合并了所有所需Map任务输出文件的新文件产生了。而那些从其他各个服务器网罗过来的 Map任务输出文件,全部删除了。

11.3Reduce

Reduce任务的最后一个阶段。

输入方面:他会准备根据自定义或默认的KeyClassValueClass构造出Reducer所需的键类型, 和值的迭代类型Iterator

输出方面:它会准备一个OutputCollector收集输出与MapTask不同,这个OutputCollector更为简单,仅仅是打开一个RecordWritercollect一次(排序完成的那个文件)write一次(写往HDFS)。

有了输入,有了输出,不断循环调用自定义的Reducer,最终,Reduce阶段完成。

 

写本文之际参看了很多牛人的大作,在这里一并感谢。

 

最后,我还有三个问题没理解,请教高手解答一下。

Des1:JobtrackerTasktracker分配任务时是先判断Tasktracker上运行的Task是否小于平均工作量,小于者向其分配Task。(假如我们这里是MapTask。)然后调用函数obtainNewMapTask()中的findNewMapTask()来查找nonRunningMapCache中的TaskInProgress
findNewMapTask
()函数会从近到远一层一层地寻找。首先是同一节点,然后在寻找同一机柜上的节点,接着寻找相同数据中心下的节点,直到找了maxLevel层结束。(这段话是我从网上看到的。没理解这句话的意思。)
Q1:
我想请问下, findNewMapTask在这里寻找的是什么? TaskTracker)我的理解是:通过寻找本任务split所在的DataNode,然后判断发送心跳的TaskTracker和本任务split所在的DataNode是不是同一主机。如果是则分配这个MapTask给发送心跳的Tracker,如果不是者返回null不进行分配。如果我理解错了,请解释下。谢谢了。

Des2:
当客户端提交任务后,首先会通过用户设置的InputFormat将文件进行划分。而hadoop默认的TextInputFormat.class.查看源码知道。TextInputFormat是继承的FileInputFormat.并且将isSplitable进行了关闭。所以默认的是不对文件进行划分。
Q2:
在运行一个MapReduce程序时,原始数据都会提前上传到HDFS文件系统,大于64M的文件都会被划分存储到多个DataNode。。假如我有一个128M的文件上传到了HDFS,那天文件应该被划分成了2份。那么TextInputFormat在处理输入时不对文件进行划分,在TaskTracker处理文件时,处理的是64M,还是128M呢?

(这个问题已经解决,应该是64M
Q3
:如果是64M是不是会开启两个TaskTracker来处理文件,又因为TextInputFormat对文件不进行划分,所以每个
TaskTracker
上只会开启一个Map Task来处理Map任务。最后两个TaskTracker启动两个Reduce生成两个文件?

分享到:
评论

相关推荐

    MapReduce 2.0源码分析与编程实

    全书分为10章,系统地介绍了HDFS存储系统,Hadoop的文件I/O系统,MapReduce2.0的框架结构和源码分析,MapReduce2.0的配置与测试,MapReduce2.0运行流程,MapReduce2.0高级程序设计以及相关特性等内容。《MapReduce...

    MapReduce2.0源码分析与实战编程

    全书分为10章,系统地介绍了HDFS存储系统,Hadoop的文件I/O系统,MapReduce 2.0的框架结构和源码分析,MapReduce 2.0的配置与测试,MapReduce 2.0运行流程,MapReduce 2.0高级程序设计以及相关特性等内容。...

    map reduce 源码分析流程

    map reduce的全部执行流程,源码分析视图

    完整版大数据课件集合7-大数据导论-第七章-MapReduce(共38页).ppt

    7.1 概述 7.2 MapReduce体系结构 7.3 MapReduce工作流程 7.4 实例分析:WordCount 7.5 MapReduce的具体应用 7.6 MapReduce编程实践

    大数据mapreduce案例

    大数据mapreduce案例介绍,包括代码解释,详解MRS工作流程

    Mapreduce实验报告.doc

    任务执行基本流程 基本流程图见下一页 首先输入收据文件被Mapreduce库函数分割成M个split集。用户定义的程序被 拷贝到机群中,其中一个是master,其它的都是worker。M个map任务和R个reduc e任务将被分配。Master...

    基于hadoop+MapReduce+Java大数据清洗和分析的基本操作流程.zip

    (3)对于大数据清洗和分析的基本操作流程 清洗不符合规范的数据以及不需要采用的特殊数据、通过字典简化数据格式(如实验第二步中用到的行为地址基础数据)、分析数据中对于生产或研究有意义的数据(如实验第五步...

    java大数据作业_5Mapreduce、数据挖掘

    课后作业 ...5.简述mapreduce流程 6.简述二次排序算法 有输入数据如下所示: 1 2 2 3 2 1 4 6 3 1 3 8 3 2 需要使用二次排序算法,得到如下处理结果: 1 2 2 1 2 3 3 1 3 2 3 8 4 6 请简述处理过程

    MapReduce编程模型在日志分析方面的应用

    本文将以对访问网页用户的日志进行分析,进而挖掘出用户兴趣点这一完整流程为例,详尽解释MapReduce模型的对应实现,涵盖MapReduce编程中对于特殊问题的处理技巧,比如机器学习算法、排序算法、索引机制、连接机制等...

    Ch5-MapReduce算法设计1

    1.MapReduce可解决哪些算法问题 2.回顾:MapReduce处理流程 3.MapReduce排序算法 4.MapReduce单词同现分析算法 5.Ma

    云计算中的MapReduce技术

    ),分析了MapReduce的基本原理,并以字数统计为例,详细介绍了作业提交、映射任务分配、映射任务执行、归约任务分配、排序、归约任务执行、作业完成等7大MapReduce计算流程,最后描述了MapReduce在云计算中的重要作用。

    MapReduceV1:Job提交流程之JobClient端分析

    我们基于Hadoop1.2.1源码分析MapReduceV1的处理流程。MapReduceV1实现中,主要存在3个主要的分布式进程(角色):JobClient、JobTracker和TaskTracker,我们主要是以这三个角色的实际处理活动为主线,并结合源码,...

    论文研究-基于Mapreduce的点度中间度算法研究 .pdf

    基于Mapreduce的点度中间度算法研究,杨成,,本文阐述了社会网络分析中的点度中间度的定义及计算原理,结合MapReduce的执行流程,设计了基于MapReduce的点度中间度的算法。设计的要

    javashuffle源码-MapReduce-Demo:Hadoop,MapReduce编程学习练手实例

    其次,所谓的MapReduce学习流程是参照老师上课所讲的PPT上的流程【某985大数据课程PPT】以及《MapReduce Design Patterns》顺序,我想老师以这样的流程授课肯定是有道理的。 该项目还在更新中,有些代码还没实现,...

    面向MapReduce的数据处理流程开发方法.pdf

    #资源达人分享计划#

    Hadoop从入门到上手企业开发

    060 MapReduce执行流程之Shuffle和排序流程以及Map端分析 061 MapReduce执行流程之Reduce端分析 062 MapReduce Shuffle过程讲解和Map Shuffle Phase讲解 063 Reduce Shuffle Phase讲解 064 源代码跟踪查看Map Task和...

    MapReduceV1:JobTracker处理Heartbeat流程分析

    我们基于Hadoop1.2.1源码分析MapReduceV1的处理流程。这篇文章的内容,更多地主要是描述处理/交互流程性的东西,大部分流程图都是经过我梳理后画出来的(开始我打算使用序列图来描述流程,但是发现很多流程在单个...

Global site tag (gtag.js) - Google Analytics