JobClient学习------作业提交与初始化
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
//conf就是作业的配置对象,读取core-site、core-default、hdfs-site/default、mapred-site/default文件里的配置信息
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
//args[]就是使用hadoop jar命令运行作业时输入/输出路径参数,这两个参数传给了main函数
if (otherArgs.length != 2) {
System.err.println("Usage: wordcount <in> <out>");
System.exit(2);//System.exit(0)表示正常退出,exit()参数非0表示非正常退出。
}
Job job = new Job(conf, "word count");
//以下就是设置job的一些运行参数,这些方法内部都会调用jobconf对象对应的方法
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//以下就是设置job的一些运行参数,这些方法内部都会调用jobconf对象对应的方法
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
可以看出作业完成了配置之后,调用了System.exit(job.waitForCompletion(true) ? 0 : 1);job.waitForCompletion(true),true表示显示作业运行过程中的信息,waitForCompletion方法实现如下:
public boolean waitForCompletion(boolean verbose
) throws IOException, InterruptedException,
ClassNotFoundException {
if (state == JobState.DEFINE) {
submit();
}
if (verbose) {
jobClient.monitorAndPrintJob(conf, info);
} else {
info.waitForCompletion();
}
return isSuccessful();
}
提交作业的时候,其状态是JobState.DEFINE,然后调用submit()方法,其实现如下所示:
public void submit() throws IOException, InterruptedException,
ClassNotFoundException {
ensureState(JobState.DEFINE);
setUseNewAPI();//使用新API // Connect to the JobTracker and submit the job
connect();
info = jobClient.submitJobInternal(conf);
super.setJobID(info.getID());
state = JobState.RUNNING;
}
使用connect()方法连接JobTracker,其实现如下:
private void connect() throws IOException, InterruptedException {
ugi.doAs(new PrivilegedExceptionAction<Object>() {
public Object run() throws IOException {
jobClient = new JobClient((JobConf) getConfiguration());
return null;
}
});
}
public JobClient(JobConf conf) throws IOException {
......
init(conf);
}
public void init(JobConf conf) throws IOException {
......
this.jobSubmitClient = createRPCProxy(JobTracker.getAddress(conf), conf);
}
private static JobSubmissionProtocol createRPCProxy(InetSocketAddress addr,
Configuration conf) throws IOException {
return (JobSubmissionProtocol) RPC.getProxy(JobSubmissionProtocol.class,
JobSubmissionProtocol.versionID, addr,
UserGroupInformation.getCurrentUser(), conf,
NetUtils.getSocketFactory(conf, JobSubmissionProtocol.class));
}
第7行:此时获得一个实现JobSubmissionProtocol 的RPC调用,即JobTracker的代理,jobSubmitClient就是JobSubmissionProtocol接口的实现类。JobSubmissionProtocol是JobClient和Jobtracker通信的桥梁。
在connect方法中创建了jobClient,在submit方法中JobClient通过submitJobInternal(conf)方法正式向JobTracker提交作业。summitJobInternal(conf
)实现如下:
public RunningJob submitJobInternal(final JobConf job
) throws FileNotFoundException,
ClassNotFoundException,
InterruptedException,
IOException {
/*
* configure the command line options correctly on the submitting dfs
*/
return ugi.doAs(new PrivilegedExceptionAction<RunningJob>() {
public RunningJob run() throws FileNotFoundException,
ClassNotFoundException,
InterruptedException,
IOException{
JobConf jobCopy = job;
Path jobStagingArea = JobSubmissionFiles.getStagingDir(JobClient.this,
jobCopy);
JobID jobId = jobSubmitClient.getNewJobId();
Path submitJobDir = new Path(jobStagingArea, jobId.toString());
jobCopy.set("mapreduce.job.dir", submitJobDir.toString());
JobStatus status = null;
try {
populateTokenCache(jobCopy, jobCopy.getCredentials()); copyAndConfigureFiles(jobCopy, submitJobDir); // get delegation token for the dir
TokenCache.obtainTokensForNamenodes(jobCopy.getCredentials(),
new Path [] {submitJobDir},
jobCopy); Path submitJobFile = JobSubmissionFiles.getJobConfPath(submitJobDir);
int reduces = jobCopy.getNumReduceTasks();
InetAddress ip = InetAddress.getLocalHost();
if (ip != null) {
job.setJobSubmitHostAddress(ip.getHostAddress());
job.setJobSubmitHostName(ip.getHostName());
}
JobContext context = new JobContext(jobCopy, jobId); // Check the output specification
if (reduces == 0 ? jobCopy.getUseNewMapper() :
jobCopy.getUseNewReducer()) {
org.apache.hadoop.mapreduce.OutputFormat<?,?> output =
ReflectionUtils.newInstance(context.getOutputFormatClass(),
jobCopy);
output.checkOutputSpecs(context);
} else {
jobCopy.getOutputFormat().checkOutputSpecs(fs, jobCopy);
} jobCopy = (JobConf)context.getConfiguration(); // Create the splits for the job
FileSystem fs = submitJobDir.getFileSystem(jobCopy);
LOG.debug("Creating splits at " + fs.makeQualified(submitJobDir));
int maps = writeSplits(context, submitJobDir);
jobCopy.setNumMapTasks(maps); // write "queue admins of the queue to which job is being submitted"
// to job file.
String queue = jobCopy.getQueueName();
AccessControlList acl = jobSubmitClient.getQueueAdmins(queue);
jobCopy.set(QueueManager.toFullPropertyName(queue,
QueueACL.ADMINISTER_JOBS.getAclName()), acl.getACLString()); // Write job file to JobTracker's fs
FSDataOutputStream out =
FileSystem.create(fs, submitJobFile,
new FsPermission(JobSubmissionFiles.JOB_FILE_PERMISSION)); // removing jobtoken referrals before copying the jobconf to HDFS
// as the tasks don't need this setting, actually they may break
// because of it if present as the referral will point to a
// different job.
TokenCache.cleanUpTokenReferral(jobCopy); try {
jobCopy.writeXml(out);
} finally {
out.close();
}
//
// 真正开始提交作业
//
printTokens(jobId, jobCopy.getCredentials());
//利用jobSumitClient调用submitJob向JobTracker提交作业
status = jobSubmitClient.submitJob(
jobId, submitJobDir.toString(), jobCopy.getCredentials());
JobProfile prof = jobSubmitClient.getJobProfile(jobId);
if (status != null && prof != null) {
return new NetworkedJob(status, prof, jobSubmitClient);
} else {
throw new IOException("Could not launch job");
}
} finally {
if (status == null) {
LOG.info("Cleaning up the staging area " + submitJobDir);
if (fs != null && submitJobDir != null)
fs.delete(submitJobDir, true);
}
}
}
});
}
下图描述了作业提交和初始化的过程:

上图中的1,2表示被调用函数被调用的顺序。
1)关于DistributedCache:
MapReduce作业文件的上传和下载都是由DistributedCache工具完成的。
2)关于复制作业运行所需要的文件到JobTracker所在的文件系统的指定目录(一般是HDFS上的某个目录)
通常而言,对于一个典型的Java MapReduce作业,可能包含以下资源。也就是需要将这些资源复制到HDFS上的某个目录
a.程序jar包:用户用Java编写的MapReduce应用程序jar包。(job.jar)
b.作业配置文件:描述MapReduce应用程序的配置信息(job.xml)
c.依赖的第三方jar包:应用程序依赖的第三方jar包,提交作业时用参数“-libjars”指定。
d.依赖的归档文件:应用程序中用到多个文件,可直接打包成归档文件,提交作业时用参数“-archives”指定。
e.依赖的普通文件:应用程序中可能用到普通文件,比如文本格式的字典文件,提交作业时用参数“-files”指定。
其实,一般复制的文件只有job.jar,job.xml,job.split,job.splitmetainfo .这些统称为作业文件。

作业文件上传到HDFS后,可能会有大量节点同时从HDFS上下载这些文件,进而产生文件访问热点现象,造成性能瓶颈。为此,JobClient上传这些文件时会调高它们的副本数(由参数mapred.submit.replication指定,默认是10)以通过分摊负载方式避免产生访问热点。
再看一下core-site.xml中的一个配置项:
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop/tmp</value>
</property>
hadoop.tmp.dir 是hadoop文件系统(HDFS)依赖的基础配置,很多路径都依赖它,并且NameNode的元数据备份等信息也会放在此这个目录下,如果不配置,其默认路径是/tmp,这里的/tmp是HDFS中的/tmp,并不是本机Linux中的/tmp,而/tmp是系统的临时目录,系统重启时往往会被清空,所以需要自定义一个持久化的数据目录。

运行一个WordCount作业,当前运行的作业的相关的各种文件在由JobClient提交作业的时候,是复制到了HDFS的某个目录上的,作业运行成功之后会再从HDFS上删除掉。
可以通过两个属性查找到当前运行作业相关的各种文件:
作业属性 属性值 说明
mapreduce.jobtracker.staging.root.dir ${hadoop.tmp.dir}/mapred/staging 复制过来的作业相关文件在HDFS上的存放位置
mapreduce.job.dir ${mapreduce.jobtracker.staging.root.dir}/${user}/.staging/${jobId} 用户{user}的某个作业相关文件的存放位置
而配置文件中hadoop.tmp.dir=/usr/local/hadoop/tmp,很容易找到WordCount作业在HDFS上的相关文件。

参考:
http://blog.sina.com.cn/s/blog_9d31d3870101dkxt.html
JobClient学习------作业提交与初始化的更多相关文章
- 【hadoop代码笔记】hadoop作业提交之汇总
一.概述 在本篇博文中,试图通过代码了解hadoop job执行的整个流程.即用户提交的mapreduce的jar文件.输入提交到hadoop的集群,并在集群中运行.重点在代码的角度描述整个流程,有些 ...
- MapReduce调度与执行原理之作业提交
前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...
- 【Hadoop代码笔记】Hadoop作业提交之客户端作业提交
1. 概要描述仅仅描述向Hadoop提交作业的第一步,即调用Jobclient的submitJob方法,向Hadoop提交作业. 2. 详细描述Jobclient使用内置的JobS ...
- Spark学习(四) -- Spark作业提交
标签(空格分隔): Spark 作业提交 先回顾一下WordCount的过程: sc.textFile("README.rd").flatMap(line => line.s ...
- 【Hadoop代码笔记】Hadoop作业提交之JobTracker等相关功能模块初始化
一.概要描述 本文重点描述在JobTracker一端接收作业.调度作业等几个模块的初始化工作.想过模块的介绍会在其他文章中比较详细的描述.受理作业提交在下一篇文章中会进行描述. 为了表达的尽可能清晰一 ...
- Spark学习之路(五)—— Spark运行模式与作业提交
一.作业提交 1.1 spark-submit Spark所有模式均使用spark-submit命令提交作业,其格式如下: ./bin/spark-submit \ --class <main- ...
- Hadoop作业提交之TaskTracker获取Task
[Hadoop代码笔记]Hadoop作业提交之TaskTracker获取Task 一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobC ...
- yarn作业提交过程源码
记录源码细节,内部有中文注释 Client 端: //最终通过ApplicationClientProtocol协议提交到RM端的ClientRMService内 package org.apache ...
- 【hadoop代码笔记】Hadoop作业提交中EagerTaskInitializationListener的作用
在整理FairScheduler实现的task调度逻辑时,注意到EagerTaskInitializationListener类.差不多应该是job提交相关的逻辑代码中最简单清楚的一个了. todo: ...
随机推荐
- DrawTool多重笔之前奏 => 通过InkAnalyzer实现图形识别
这里要介绍的是通过InkAnalyzer来实现简单图形的识别,例如圆,椭圆,正方形,三角形等,当然你也可以通过扩展来实现自定义图形的识别,在使用InkAnalyzer前,你需要引用IAWinFX.dl ...
- DB2物化表
DB2物化查询表(MQT)是DB2数据库中一类特殊的表 物化表和视图的区别 物化表是一个查询结果集,视图是一个SQL语句. 以下是一个简单例子(说明物化表) 1.创建表,插入测试数据 ----创建表 ...
- hdu 2102 A计划
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2102 A计划 Description 可怜的公主在一次次被魔王掳走一次次被骑士们救回来之后,而今,不幸 ...
- Android 编译使用高版本的Java
讨论的链接 http://bbs.csdn.net/topics/390977000 问题很容易解决,就是sdk\tools\ant\build.xml里面的配置不对,把 <property n ...
- Window7上搭建symfony开发环境(PEAR)
http://blog.csdn.net/kunshan_shenbin/article/details/7162243 1. 更新PEAR 进入PHP所在目录,找到go-pear.bat并双击. 一 ...
- 条款7:为多态基类声明virtual析构函数
C++明确指出:当派生类对象是由一个基类指针释放的,而基类中的析构函数不是虚函数,那么结果是未定义的.其实我们执行时其结果就是:只调用最上层基类的析构函数,派生类及其中间基类的析构函数得不到调用. # ...
- ALTERA MAX10官方评估板,新鲜出炉!
刚刚拿到骏龙提供的ALTERA MAX10官方评估板,还热乎呢,呵呵!赶紧跟大家分享一下 板子很简单,把IO口都扩展出来了,其他功能基本上没有. FPGA型号是10M08SAE144C8GES,144 ...
- Python实现ID3(信息增益)
Python实现ID3(信息增益) 运行环境 Pyhton3 treePlotter模块(画图所需,不画图可不必) matplotlib(如果使用上面的模块必须) 计算过程 st=>start: ...
- Altera USB Blaster 仿真器(EPM240仿制版
转载:http://tigerwang202.blogbus.com/logs/35981280.html 其他很好的资料:http://bbs.ednchina.com/BLOG_ARTICLE_1 ...
- SQLite数据库的基本API函数
1 .打开数据库: 说明:打开一个数据库,文件名不一定要存在,如果此文件不存在, sqlite 会自动创建.第一个参数指文件名,第二个参数则是定义的 sqlite3 ** 结构体指针(关键数据结构), ...