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学习------作业提交与初始化的更多相关文章

  1. 【hadoop代码笔记】hadoop作业提交之汇总

    一.概述 在本篇博文中,试图通过代码了解hadoop job执行的整个流程.即用户提交的mapreduce的jar文件.输入提交到hadoop的集群,并在集群中运行.重点在代码的角度描述整个流程,有些 ...

  2. MapReduce调度与执行原理之作业提交

    前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...

  3. 【Hadoop代码笔记】Hadoop作业提交之客户端作业提交

    1.      概要描述仅仅描述向Hadoop提交作业的第一步,即调用Jobclient的submitJob方法,向Hadoop提交作业. 2.      详细描述Jobclient使用内置的JobS ...

  4. Spark学习(四) -- Spark作业提交

    标签(空格分隔): Spark 作业提交 先回顾一下WordCount的过程: sc.textFile("README.rd").flatMap(line => line.s ...

  5. 【Hadoop代码笔记】Hadoop作业提交之JobTracker等相关功能模块初始化

    一.概要描述 本文重点描述在JobTracker一端接收作业.调度作业等几个模块的初始化工作.想过模块的介绍会在其他文章中比较详细的描述.受理作业提交在下一篇文章中会进行描述. 为了表达的尽可能清晰一 ...

  6. Spark学习之路(五)—— Spark运行模式与作业提交

    一.作业提交 1.1 spark-submit Spark所有模式均使用spark-submit命令提交作业,其格式如下: ./bin/spark-submit \ --class <main- ...

  7. Hadoop作业提交之TaskTracker获取Task

    [Hadoop代码笔记]Hadoop作业提交之TaskTracker获取Task 一.概要描述 在上上一篇博文和上一篇博文中分别描述了jobTracker和其服务(功能)模块初始化完成后,接收JobC ...

  8. yarn作业提交过程源码

    记录源码细节,内部有中文注释 Client 端: //最终通过ApplicationClientProtocol协议提交到RM端的ClientRMService内 package org.apache ...

  9. 【hadoop代码笔记】Hadoop作业提交中EagerTaskInitializationListener的作用

    在整理FairScheduler实现的task调度逻辑时,注意到EagerTaskInitializationListener类.差不多应该是job提交相关的逻辑代码中最简单清楚的一个了. todo: ...

随机推荐

  1. xtrabackup之Innobackupex全备数据库

    一.Xtrabackup是什么: Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品. ...

  2. Linux下自带的regex

    Linux下可直接用regex.h来支持正则表达式. Android同样也有该头文件,可认为Android也是支持的. #include <sys/types.h> #include &l ...

  3. Visual Studio 2013中添加mimeType

    事例: cd C:\Program files\IIS Expressappcmd set config /section:staticContent /+[fileExtension='.json' ...

  4. Mybatis 实现传入参数是表名

    <select id="totals" resultType="string"> select count(*) from ${table} < ...

  5. chattr 与 lsattr 命令详解

    PS:有时候你发现用root权限都不能修改某个文件,大部分原因是曾经用chattr命令锁定该文件了.chattr命令的作用很大,其中一些功能是由Linux内核版本来支持的,不过现在生产绝大部分跑的li ...

  6. 九度oj 1521 二叉树的镜像

    原题链接:http://ac.jobdu.com/problem.php?pid=1521 水题,如下.. #include<algorithm> #include<iostream ...

  7. JavaScript 将多个引用(样式或者脚本)放入一个文件进行引用

    1.将样式放入一个文件进行引用 @import url("../media/css/bootstrap.min.css"); @import url("../media/ ...

  8. Qt之SQL数据库

    ---------------------------- http://blog.csdn.net/reborntercel/article/details/6991147 http://blog.c ...

  9. Java Day 12

    包 编译格式 javac -d . **.java 包之间的访问 类找不到: 类名写错,包名.类名 包不存在:指定classpath 其他包的类无法访问:权限 public protected 包导入 ...

  10. 桥接模式和NAT模式

    linux的目录结构 配置ip三种 模式 桥接模式 nat模式(VMnet8) 配置网关 DHCP动态分配IP设置 linux的目录结构 配置ip三种 模式 桥接模式 (1) 设置主系统的" ...