Hadoop总结篇之三---一个Job到底被提交到哪去了
我们会定义Job,我们会定义map和reduce程序。那么,这个Job到底是怎么提交的?提交到哪去了?它到底和集群怎么进行交互的呢?
这篇文章将从头讲起。
开发hadoop的程序时,一共有三大块,也就是Driver、map、reduce,在Driver中,我们要定义Configuration,定义Job,在mian方法最后,往往会以这么一段代码结尾:
if (!job.waitForCompletion(true))
return;
而这句的作用,就是提交了我们的Job。进入代码里(其实就是Job类)我们可以看到具体实现:
public boolean waitForCompletion(boolean verbose
) throws IOException, InterruptedException,
ClassNotFoundException {
if (state == JobState.DEFINE) {
//这句是重点,提交。那么从代码里看出这个似乎是异步提交啊,否则后面的监测怎么执行呢?我们拭目以待
submit();
}
if (verbose) {
monitorAndPrintJob();
} else {
// get the completion poll interval from the client.
//从配置里取得轮训的间隔时间,来分析当前job是否执行完毕
int completionPollIntervalMillis =
Job.getCompletionPollInterval(cluster.getConf());
while (!isComplete()) {
try {
Thread.sleep(completionPollIntervalMillis);
} catch (InterruptedException ie) {
}
}
}
return isSuccessful();
}
依然在Job.class里,这个方法主要动作有二,一是找到集群,二是讲Job提交到集群
public void submit()
throws IOException, InterruptedException, ClassNotFoundException {
ensureState(JobState.DEFINE);
setUseNewAPI();
//连接集群/master
connect();
//构造提交器
final JobSubmitter submitter =
getJobSubmitter(cluster.getFileSystem(), cluster.getClient());
status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() {
public JobStatus run() throws IOException, InterruptedException,
ClassNotFoundException {
//提交
return submitter.submitJobInternal(Job.this, cluster);
}
});
state = JobState.RUNNING;
LOG.info("The url to track the job: " + getTrackingURL());
}
我们继续往下看,看下提交的时候都做了什么?
JobStatus submitJobInternal(Job job, Cluster cluster)
throws ClassNotFoundException, InterruptedException, IOException { // 检查输出目录合法性(已存在?没指定?),这就是为什么每次提交作业,总是这个 错比较靠前的报出来
checkSpecs(job); Configuration conf = job.getConfiguration();
// 将框架提交到集群缓存(具体左右还未知?)
addMRFrameworkToDistributedCache(conf); // 获得登录区,用以存放作业执行过程中用到的文件,默认位置/tmp/hadoop-yarn/staging/root/.staging
// ,可通过yarn.app.mapreduce.am.staging-dir修改
Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);
// configure the command line options correctly on the submitting dfs
// 这是获取和设置提交job机器的地址和主机名
InetAddress ip = InetAddress.getLocalHost();
if (ip != null) {
submitHostAddress = ip.getHostAddress();
submitHostName = ip.getHostName();
conf.set(MRJobConfig.JOB_SUBMITHOST, submitHostName);
conf.set(MRJobConfig.JOB_SUBMITHOSTADDR, submitHostAddress);
}
// 取得当前Job的ID(后面详细关注此处)
JobID jobId = submitClient.getNewJobID();
job.setJobID(jobId);
// 作业提交目录
Path submitJobDir = new Path(jobStagingArea, jobId.toString());
JobStatus status = null;
try {
conf.set(MRJobConfig.USER_NAME, UserGroupInformation.getCurrentUser().getShortUserName());
conf.set("hadoop.http.filter.initializers",
"org.apache.hadoop.yarn.server.webproxy.amfilter.AmFilterInitializer");
conf.set(MRJobConfig.MAPREDUCE_JOB_DIR, submitJobDir.toString());
LOG.debug("Configuring job " + jobId + " with " + submitJobDir + " as the submit dir");
// get delegation token for the dir
TokenCache.obtainTokensForNamenodes(job.getCredentials(), new Path[] { submitJobDir }, conf); populateTokenCache(conf, job.getCredentials()); // generate a secret to authenticate shuffle transfers
if (TokenCache.getShuffleSecretKey(job.getCredentials()) == null) {
KeyGenerator keyGen;
try { int keyLen = CryptoUtils.isShuffleEncrypted(conf)
? conf.getInt(MRJobConfig.MR_ENCRYPTED_INTERMEDIATE_DATA_KEY_SIZE_BITS,
MRJobConfig.DEFAULT_MR_ENCRYPTED_INTERMEDIATE_DATA_KEY_SIZE_BITS)
: SHUFFLE_KEY_LENGTH;
keyGen = KeyGenerator.getInstance(SHUFFLE_KEYGEN_ALGORITHM);
keyGen.init(keyLen);
} catch (NoSuchAlgorithmException e) {
throw new IOException("Error generating shuffle secret key", e);
}
SecretKey shuffleKey = keyGen.generateKey();
TokenCache.setShuffleSecretKey(shuffleKey.getEncoded(), job.getCredentials());
}
// 从本地copy文件到hdfs,比如我们提交的wordcount.jar
copyAndConfigureFiles(job, submitJobDir); Path submitJobFile = JobSubmissionFiles.getJobConfPath(submitJobDir); // Create the splits for the job,其实也就是确定了map的数量
LOG.debug("Creating splits at " + jtFs.makeQualified(submitJobDir));
int maps = writeSplits(job, submitJobDir);
conf.setInt(MRJobConfig.NUM_MAPS, maps);
LOG.info("number of splits:" + maps); // write "queue admins of the queue to which job is being submitted"
// to job file.
String queue = conf.get(MRJobConfig.QUEUE_NAME, JobConf.DEFAULT_QUEUE_NAME);
AccessControlList acl = submitClient.getQueueAdmins(queue);
conf.set(toFullPropertyName(queue, QueueACL.ADMINISTER_JOBS.getAclName()), acl.getAclString()); // 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(conf); if (conf.getBoolean(MRJobConfig.JOB_TOKEN_TRACKING_IDS_ENABLED,
MRJobConfig.DEFAULT_JOB_TOKEN_TRACKING_IDS_ENABLED)) {
// Add HDFS tracking ids
ArrayList<String> trackingIds = new ArrayList<String>();
for (Token<? extends TokenIdentifier> t : job.getCredentials().getAllTokens()) {
trackingIds.add(t.decodeIdentifier().getTrackingId());
}
conf.setStrings(MRJobConfig.JOB_TOKEN_TRACKING_IDS,
trackingIds.toArray(new String[trackingIds.size()]));
} // Set reservation info if it exists
ReservationId reservationId = job.getReservationId();
if (reservationId != null) {
conf.set(MRJobConfig.RESERVATION_ID, reservationId.toString());
}
// Write job file to submit dir
writeConf(conf, submitJobFile); //
// Now, actually submit the job (using the submit name)
//
printTokens(jobId, job.getCredentials());
//提交!!!!!!!!
status = submitClient.submitJob(jobId, submitJobDir.toString(), job.getCredentials());
if (status != null) {
return status;
} else {
throw new IOException("Could not launch job");
}
} finally {
if (status == null) {
LOG.info("Cleaning up the staging area " + submitJobDir);
if (jtFs != null && submitJobDir != null)
jtFs.delete(submitJobDir, true); }
}
}
那么这个最终提交用到的submitClient是哪来的?他是怎么定义的?
它是上文提到的,连接集群的时候创建的。这个集群定义了很多信息:客户端信息、用户组信息、文件系统信息,配置信息,历史job目录,系统目录等。其中客户端信息,提供了初始化方法,如下:
public Cluster(InetSocketAddress jobTrackAddr, Configuration conf)
throws IOException {
this.conf = conf;
this.ugi = UserGroupInformation.getCurrentUser();
//初始化是重点
initialize(jobTrackAddr, conf);
}
具体看下初始化过程:
private void initialize(InetSocketAddress jobTrackAddr, Configuration conf)
throws IOException { synchronized (frameworkLoader) {
for (ClientProtocolProvider provider : frameworkLoader) {
LOG.debug("Trying ClientProtocolProvider : "
+ provider.getClass().getName());
//根据配置,创建客户端协议提供者
ClientProtocol clientProtocol = null;
try {
if (jobTrackAddr == null) {
//提供者返回的是一个具体的协议
clientProtocol = provider.create(conf);
} else {
clientProtocol = provider.create(jobTrackAddr, conf);
} if (clientProtocol != null) {
clientProtocolProvider = provider;
//看到没?协议是什么?协议其实就是个类,里面封装了一些约定好的属性,以及操作这些属性的方法。实例化为对象后,就是一个可用于通信的客户端
client = clientProtocol;
LOG.debug("Picked " + provider.getClass().getName()
+ " as the ClientProtocolProvider");
break;
}
else {
LOG.debug("Cannot pick " + provider.getClass().getName()
+ " as the ClientProtocolProvider - returned null protocol");
}
}
catch (Exception e) {
LOG.info("Failed to use " + provider.getClass().getName()
+ " due to error: " + e.getMessage());
}
}
} if (null == clientProtocolProvider || null == client) {
throw new IOException(
"Cannot initialize Cluster. Please check your configuration for "
+ MRConfig.FRAMEWORK_NAME
+ " and the correspond server addresses.");
}
}
创建客户端协议提供者,用java.util.ServiceLoader,目前包含两个具体实现,LocalClientProtocolProvider(本地作业) YarnClientProtocolProvider(Yarn作业),此处会根据mapreduce.framework.name的配置选择使用哪个创建相应的客户端。
而YarnClientProtocolProvider的本质是创建了一个YarnRunner对象
public ClientProtocol create(Configuration conf) throws IOException {
if (MRConfig.YARN_FRAMEWORK_NAME.equals(conf.get(MRConfig.FRAMEWORK_NAME))) {
return new YARNRunner(conf);
}
return null;
}
YarnRunner对象是干什么的?根据注释解释,是让当前JobClient在yarn上运行的。提供一些提交Job啊,杀死Job之类的方法。它实现了ClientProtocol接口,上面讲的提交的最后一步,其实最终就是调用了YarnRunner的submitJob方法。
它里面封装了ResourceMgrDelegate委托,委托的方法正是YarnClient类里的提交方法submitApplication。这样,当前作业(Application)提交过程,走到了YarnClient阶段。
总结:Job目前提交到了YarnClient实例中。那么YarnClient接下来怎么处理呢?
Hadoop总结篇之三---一个Job到底被提交到哪去了的更多相关文章
- 【PHP开发篇】一个统计客户端商机提交的获取IP地址
1.对客服提交数据的ip地址记录. 获取ip地址的方法: public function getIP() { global $ip; if (getenv("HTTP_X_REAL_IP&q ...
- Hadoop总结篇之一------开篇
从今天开始新的系列:Hadoop总结篇 之前的hadoop学习篇由于是学习过程中随手记下来的一些内容,不具有系统性.所以在这个系列中,将凭着这段时间的研究心得,来记录一些自认为比较重要的东西. 本系列 ...
- Hadoop学习篇 2 初识 Hadoop
在一个全配置的集群上,运行Hadoop意味着在网络分布的不同服务器上运行一组守护进程 (daemons),这些守护进程或运行在单个服务器上,或运行与多个服务器上,他们包括: (1) NameNode( ...
- 【转】C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。
C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子. 标签: c#objectnewlineexceptionbytestring 2010-05-17 01:10 117109人阅读 ...
- 查找一个Class到底在那一个jar文件里
整理自己的一些笔记,发觉这个命令 ,看起来是用来找一个Class到底在那一个jar文件里的. 虽然没有再测一下,估计是好使的. 先在博客园里记下来,防止自己忘掉. findstr /S /M org. ...
- JavaWeb学习总结第二篇--第一个JavaWeb程序
JavaWeb学习总结第二篇—第一个JavaWeb程序 最近我在学院工作室学习并加入到研究生的项目中,在学长学姐的带领下,进入项目实践中,为该项目实现一个框架(用已有框架进行改写).于是我在这里记录下 ...
- webrtc进阶-信令篇-之三:信令、stun、turn、ice
webRTC支持点对点通讯,但是webRTC仍然需要服务端: . 协调通讯过程中客户端之间需要交换元数据, 如一个客户端找到另一个客户端以及通知另一个客户端开始通讯. . 需要处理NAT(网 ...
- hadoop运行原理之Job运行(二) Job提交及初始化
本篇主要介绍Job从客户端提交到JobTracker及其被初始化的过程. 以WordCount为例,以前的程序都是通过JobClient.runJob()方法来提交Job,但是现在大多用Job.wai ...
- SVN 安装配置详解,包含服务器和客户端,外带一个项目演示,提交,更改,下载历史版本,撤销
本次要介绍的是svn版本管理工具包含2个: 服务器端:visualsvn server 下载地址为:https://www.visualsvn.com/server/download/ 此处演示的 ...
随机推荐
- C#代码规范
C#代码规范 一.文件命名 1 文件名 文件名统一使用帕斯卡命名法,以C#类名命名,拓展名小写. 示例: GameManager.cs 2 文件注释 每个文件头须包含注释说明,文件头位置指的是文件最 ...
- Cruehead.1
查壳 没有 我拖 alt+F9 到上面 入口处 下断 关键跳 略过 就没了 要实现 强暴 直接过... 仔细来看看... 那两个调用 都下断 看看 判断 ...
- 《看板与Scrum》读书笔记
看板的朴素思想:在制品(work-in-progress, WIP)必须被限制 WIP上限和拉动式生产 1. Scrum与看板简述 Scrum:组织拆分,工作拆分,开发时间拆分,优化发布计划,过程优化 ...
- Rally的敏捷小册子
来自为知笔记(Wiz)
- IOS开发官方文档随笔
马上着手开发IOS应用程序 创建第一个单视图应用 ###main 方法 int main(int argc, char * argv[]) { @autoreleasepool { return UI ...
- CSS---解决内容过多就会出文本溢出(显示在区域外面,不换行的情况)
当我们设置我的的div,或者其它文本框固定宽度之后,文本内容过多就会出文本溢出(显示在区域外面,不换行的情况). 这时我们可以使用Css中的几个属于来解.有以下的三个属于可以解决问题: 1,word- ...
- iOS纯代码适配masonry中mas_的问题
//equalto 和 mas_equalto 是有区别的.但是我们不打算去了解,可以通过添加以下代码来统一. //注意!! 宏定义必须要放在 import 引入头文件之前! //define thi ...
- URL参数为url,获取不到部分参数问题
url1中的参数含有url2,在页面上获取url时发现url后面跟的参数获取不到,其实是浏览器把url2中&后的参数作为url1的参数来处理了. 如:http://www.ilcng.com/ ...
- 15个jQuery小技巧
1.返回顶部按钮通过使用jQuery中的animate 和scrollTop 方法,不用插件就可以创建一个滚动到顶部的简单动画:// Back to top $('.top').click(funct ...
- 兼容PC手机端字体
各平台的主流字体支持情况 各系统的默认字体和常用字体: 系统 默认西文字体 默认中文字体 其他常用西文字体 其他常用中文字体 Windows 宋体 宋体 Tahoma.Arial.Verdana.Ge ...