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: ...
随机推荐
- xtrabackup之Innobackupex全备数据库
一.Xtrabackup是什么: Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品. ...
- Linux下自带的regex
Linux下可直接用regex.h来支持正则表达式. Android同样也有该头文件,可认为Android也是支持的. #include <sys/types.h> #include &l ...
- Visual Studio 2013中添加mimeType
事例: cd C:\Program files\IIS Expressappcmd set config /section:staticContent /+[fileExtension='.json' ...
- Mybatis 实现传入参数是表名
<select id="totals" resultType="string"> select count(*) from ${table} < ...
- chattr 与 lsattr 命令详解
PS:有时候你发现用root权限都不能修改某个文件,大部分原因是曾经用chattr命令锁定该文件了.chattr命令的作用很大,其中一些功能是由Linux内核版本来支持的,不过现在生产绝大部分跑的li ...
- 九度oj 1521 二叉树的镜像
原题链接:http://ac.jobdu.com/problem.php?pid=1521 水题,如下.. #include<algorithm> #include<iostream ...
- JavaScript 将多个引用(样式或者脚本)放入一个文件进行引用
1.将样式放入一个文件进行引用 @import url("../media/css/bootstrap.min.css"); @import url("../media/ ...
- Qt之SQL数据库
---------------------------- http://blog.csdn.net/reborntercel/article/details/6991147 http://blog.c ...
- Java Day 12
包 编译格式 javac -d . **.java 包之间的访问 类找不到: 类名写错,包名.类名 包不存在:指定classpath 其他包的类无法访问:权限 public protected 包导入 ...
- 桥接模式和NAT模式
linux的目录结构 配置ip三种 模式 桥接模式 nat模式(VMnet8) 配置网关 DHCP动态分配IP设置 linux的目录结构 配置ip三种 模式 桥接模式 (1) 设置主系统的" ...