• JobClient学习------作业提交与初始化


     1 public static void main(String[] args) throws Exception {
     2 Configuration conf = new Configuration();
     3 //conf就是作业的配置对象,读取core-site、core-default、hdfs-site/default、mapred-site/default文件里的配置信息        
     4  String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
     5 //args[]就是使用hadoop jar命令运行作业时输入/输出路径参数,这两个参数传给了main函数
     6     if (otherArgs.length != 2) {
     7       System.err.println("Usage: wordcount <in> <out>");
     8       System.exit(2);//System.exit(0)表示正常退出,exit()参数非0表示非正常退出。
     9     }
    10 
    11     Job job = new Job(conf, "word count");    
    12 //以下就是设置job的一些运行参数,这些方法内部都会调用jobconf对象对应的方法
    13     job.setJarByClass(WordCount.class);
    14     job.setMapperClass(TokenizerMapper.class);
    15     job.setCombinerClass(IntSumReducer.class);
    16     job.setReducerClass(IntSumReducer.class);
    17     job.setOutputKeyClass(Text.class);
    18     job.setOutputValueClass(IntWritable.class);
    19 //以下就是设置job的一些运行参数,这些方法内部都会调用jobconf对象对应的方法
    20     FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
    21     FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
    22     System.exit(job.waitForCompletion(true) ? 0 : 1);
    23 }
       可以看出作业完成了配置之后,调用了System.exit(job.waitForCompletion(true) ? 0 : 1);job.waitForCompletion(true),true表示显示作业运行过程中的信息,waitForCompletion方法实现如下:
     1 public boolean waitForCompletion(boolean verbose
     2                                    ) throws IOException, InterruptedException,
     3                                             ClassNotFoundException {
     4     if (state == JobState.DEFINE) {
     5       submit();
     6     }
     7     if (verbose) {
     8       jobClient.monitorAndPrintJob(conf, info);
     9     } else {
    10       info.waitForCompletion();
    11     }
    12     return isSuccessful();
    13   }

    提交作业的时候,其状态是JobState.DEFINE,然后调用submit()方法,其实现如下所示:

     1 public void submit() throws IOException, InterruptedException, 
     2                               ClassNotFoundException {
     3     ensureState(JobState.DEFINE);
     4     setUseNewAPI();//使用新API
     5     
     6     // Connect to the JobTracker and submit the job
     7     connect();
     8     info = jobClient.submitJobInternal(conf);
     9     super.setJobID(info.getID());
    10     state = JobState.RUNNING;
    11    }

    使用connect()方法连接JobTracker,其实现如下:

    1  private void connect() throws IOException, InterruptedException {
    2     ugi.doAs(new PrivilegedExceptionAction<Object>() {
    3       public Object run() throws IOException {
    4         jobClient = new JobClient((JobConf) getConfiguration());    
    5         return null;
    6       }
    7     });
    8   }
     1 public JobClient(JobConf conf) throws IOException {
     2     ......
     3     init(conf);
     4   }
     5 public void init(JobConf conf) throws IOException {
     6      ......
     7      this.jobSubmitClient = createRPCProxy(JobTracker.getAddress(conf), conf);
     8   }
     9   private static JobSubmissionProtocol createRPCProxy(InetSocketAddress addr,
    10       Configuration conf) throws IOException {
    11     return (JobSubmissionProtocol) RPC.getProxy(JobSubmissionProtocol.class,
    12         JobSubmissionProtocol.versionID, addr,
    13         UserGroupInformation.getCurrentUser(), conf,
    14         NetUtils.getSocketFactory(conf, JobSubmissionProtocol.class));
    15   }
    16  
    1718  

    第7行:此时获得一个实现JobSubmissionProtocol 的RPC调用,即JobTracker的代理,jobSubmitClient就是JobSubmissionProtocol接口的实现类。JobSubmissionProtocol是JobClient和Jobtracker通信的桥梁。

    在connect方法中创建了jobClient,在submit方法中JobClient通过submitJobInternal(conf)方法正式向JobTracker提交作业。summitJobInternal(conf

    )实现如下:

      1 public RunningJob submitJobInternal(final JobConf job
      2                                ) throws FileNotFoundException, 
      3                                         ClassNotFoundException,
      4                                         InterruptedException,
      5                                         IOException {
      6     /*
      7      * configure the command line options correctly on the submitting dfs
      8      */
      9     return ugi.doAs(new PrivilegedExceptionAction<RunningJob>() {
     10       public RunningJob run() throws FileNotFoundException, 
     11       ClassNotFoundException,
     12       InterruptedException,
     13       IOException{
     14         JobConf jobCopy = job;
     15         Path jobStagingArea = JobSubmissionFiles.getStagingDir(JobClient.this,
     16             jobCopy);
     17         JobID jobId = jobSubmitClient.getNewJobId();
     18         Path submitJobDir = new Path(jobStagingArea, jobId.toString());
     19         jobCopy.set("mapreduce.job.dir", submitJobDir.toString());
     20         JobStatus status = null;
     21         try {
     22           populateTokenCache(jobCopy, jobCopy.getCredentials());
     23 
     24           copyAndConfigureFiles(jobCopy, submitJobDir);
     25 
     26           // get delegation token for the dir
     27           TokenCache.obtainTokensForNamenodes(jobCopy.getCredentials(),
     28                                               new Path [] {submitJobDir},
     29                                               jobCopy);
     30 
     31           Path submitJobFile = JobSubmissionFiles.getJobConfPath(submitJobDir);
     32           int reduces = jobCopy.getNumReduceTasks();
     33           InetAddress ip = InetAddress.getLocalHost();
     34           if (ip != null) {
     35             job.setJobSubmitHostAddress(ip.getHostAddress());
     36             job.setJobSubmitHostName(ip.getHostName());
     37           }
     38           JobContext context = new JobContext(jobCopy, jobId);
     39 
     40           // Check the output specification
     41           if (reduces == 0 ? jobCopy.getUseNewMapper() : 
     42             jobCopy.getUseNewReducer()) {
     43             org.apache.hadoop.mapreduce.OutputFormat<?,?> output =
     44               ReflectionUtils.newInstance(context.getOutputFormatClass(),
     45                   jobCopy);
     46             output.checkOutputSpecs(context);
     47           } else {
     48             jobCopy.getOutputFormat().checkOutputSpecs(fs, jobCopy);
     49           }
     50           
     51           jobCopy = (JobConf)context.getConfiguration();
     52 
     53           // Create the splits for the job
     54           FileSystem fs = submitJobDir.getFileSystem(jobCopy);
     55           LOG.debug("Creating splits at " + fs.makeQualified(submitJobDir));
     56           int maps = writeSplits(context, submitJobDir);
     57           jobCopy.setNumMapTasks(maps);
     58 
     59           // write "queue admins of the queue to which job is being submitted"
     60           // to job file.
     61           String queue = jobCopy.getQueueName();
     62           AccessControlList acl = jobSubmitClient.getQueueAdmins(queue);
     63           jobCopy.set(QueueManager.toFullPropertyName(queue,
     64               QueueACL.ADMINISTER_JOBS.getAclName()), acl.getACLString());
     65 
     66           // Write job file to JobTracker's fs        
     67           FSDataOutputStream out = 
     68             FileSystem.create(fs, submitJobFile,
     69                 new FsPermission(JobSubmissionFiles.JOB_FILE_PERMISSION));
     70 
     71           // removing jobtoken referrals before copying the jobconf to HDFS
     72           // as the tasks don't need this setting, actually they may break
     73           // because of it if present as the referral will point to a
     74           // different job.
     75           TokenCache.cleanUpTokenReferral(jobCopy);
     76 
     77           try {
     78             jobCopy.writeXml(out);
     79           } finally {
     80             out.close();
     81           }
     82           //
     83           // 真正开始提交作业
     84           //
     85           printTokens(jobId, jobCopy.getCredentials());
     86        //利用jobSumitClient调用submitJob向JobTracker提交作业
     87           status = jobSubmitClient.submitJob(
     88               jobId, submitJobDir.toString(), jobCopy.getCredentials());
     89           JobProfile prof = jobSubmitClient.getJobProfile(jobId);
     90           if (status != null && prof != null) {
     91             return new NetworkedJob(status, prof, jobSubmitClient);
     92           } else {
     93             throw new IOException("Could not launch job");
     94           }
     95         } finally {
     96           if (status == null) {
     97             LOG.info("Cleaning up the staging area " + submitJobDir);
     98             if (fs != null && submitJobDir != null)
     99               fs.delete(submitJobDir, true);
    100           }
    101         }
    102       }
    103     });
    104   }

     下图描述了作业提交和初始化的过程:

     上图中的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
  • 相关阅读:
    斐波那契数列变形
    poj 1061 青蛙的约会+拓展欧几里得+题解
    Leading and Trailing LightOJ
    HDU-1576 A/B 基础数论+解题报告
    swal() 弹出层的用法
    jqurey.running.min.js运动的字体效果
    echarts中dataZoom的使用
    echarts动态添加数据
    设备适配尺寸
    sublime Text3 插件
  • 原文地址:https://www.cnblogs.com/lz3018/p/4925758.html
Copyright © 2020-2023  润新知