1.Job提交
Job提交即在客户端调用job.submit()或者waitForCompletion()。submit方法中创建一个JobSubmitter对象,并调用其submitJobInternal()方法。其执行过程如下:
- 向resource manager(YARN)申请一个Job ID。
- 检查job的输出设置,例如输出目录是否已经存在。
- 计算输入分片数量。
- 拷贝需要的资源到HDFS,例如jar文件,配置文件以及计算好的输入分片。目的目录由job id命名。
- 调用resource manager的submitApplication()提交job。
2.Job初始化
- resource manager将提交请求传输给node manager(YARN), 并由node manager创建一个容器。resource manager在容器内创建一个MRAppMaster的进程,并由node manager管理。
- MRAppMaster初始化job,并创建多个用于跟踪job运行情况和完成报告的对象。
- 接着MRAppMaster查询计算好的分片数量,并为每一个分片创建一个map task。再根据mapreduce.job.reduces属性创建reduce task。(也可以在job的setNumReduceTasks()中设置)。
- 然后会分两种情况,对于小任务(小于10个mapper,只有一个reducer,输入块小于HDFS块),也叫uber task。这种情况下,MRAppMaster会将任务放在自己的JVM中运行。对其他的任务,还是按照分布式的运行方式。
- 最后,调用OutputCommitter的setupJob()方法。默认的是FileOutputCommitter,会创建输出文件夹和临时的工作文件夹。
3.task分配
总体思路就是,map任务在reduce任务之前,因为在Reduce任务的sort阶段前,必须执行完全部map任务。reduce任务仅在map任务执行完毕5%后开始执行。
reduce任务可以在任何节点执行,但map任务优先在存有对应数据的节点。
同时,还有内存及CPU的需求需要满足,hadoop默认的要求是1024Mb内存和一个虚拟核。此项可配置。
4.task执行
一旦task从resource manager获得所需的资源,MRAppMaster会通知node manager启动task所在的容器。task由一个主类是YarnChild的java应用执行。在执行task之前,YarnChild将job配置文件、jar文件和其他文件从分布式缓存存到本地。
5.进度与状态更新
更新的内容主要包括
- job或task中的状态(运行中、成功、失败)
- task进度
- job的计数器
- 用户自定义的状态信息
关于进度,map的进度即处理输入文件的比例,而reduce的情况比较复杂,因为reduce过程分为三个阶段,copy,sort和reduce。但还是可以根据在每一阶段中处理数据的比例大致算出task的进度。
以下操作算作task进度中:
- 读取输入记录
- 写出输出记录
- 发送状态信息(Reporter或TaskAttempContext的setStatus()方法)
- 增加计数器(Reporter的incrCounter()或Counter的increment()方法)
- 调用Reporter或TaskAttempContext的progress()
客户端每秒查询MRAppMaster一次,获得最新的状态。也可以调用job.getStatus()获得状态。
6.job完成
当MRAppMaster收到job中最后一个task完成的通知,它将自己的状态改变为“成功”,当job查询状态时,得知job完成,它就通知用户,并返回waitForCompletion()。