hadoop2.2.0、centos6.5


hadoop任务的提交常用的两种,一种是测试常用的IDE远程提交,另一种就是生产上用的客户端命令行提交


通用的任务程序提交步骤为:

1.将程序打成jar包;

2.将jar包上传到HDFS上;

3.用命令行提交HDFS上的任务程序。


跟着提交步骤从命令行提交开始

最简单的提交命令应该如:

  1. hadoop jar /home/hadoop/hadoop-2.2.0/hadoop-examples.jar wordcount inputPath outputPath

在名为hadoop的shell 命令文件中当参数为jar时

确定了要运行的CLASS文件和环境变量后最后执行了了exec命令来运行


看org.apache.hadoop.util.RunJar类的main方法

  1. public static void main(String[] args) throws Throwable {
  2. String usage = "RunJar jarFile [mainClass] args...";
  3. //验证提交的参数数量
  4. if (args.length < 1) {
  5. System.err.println(usage);
  6. System.exit(-1);
  7. }
  8. //验证jar文件是否存在
  9. int firstArg = 0;
  10. String fileName = args[firstArg++];
  11. File file = new File(fileName);
  12. if (!file.exists() || !file.isFile()) {
  13. System.err.println("Not a valid JAR: " + file.getCanonicalPath());
  14. System.exit(-1);
  15. }
  16. String mainClassName = null;
  17.  
  18. JarFile jarFile;
  19. try {
  20. jarFile = new JarFile(fileName);
  21. } catch(IOException io) {
  22. throw new IOException("Error opening job jar: " + fileName)
  23. .initCause(io);
  24. }
  25. //验证是否存在main方法
  26. Manifest manifest = jarFile.getManifest();
  27. if (manifest != null) {
  28. mainClassName = manifest.getMainAttributes().getValue("Main-Class");
  29. }
  30. jarFile.close();
  31.  
  32. if (mainClassName == null) {
  33. if (args.length < 2) {
  34. System.err.println(usage);
  35. System.exit(-1);
  36. }
  37. mainClassName = args[firstArg++];
  38. }
  39. mainClassName = mainClassName.replaceAll("/", ".");
  40. //设置临时目录并验证
  41. File tmpDir = new File(new Configuration().get("hadoop.tmp.dir"));
  42. ensureDirectory(tmpDir);
  43.  
  44. final File workDir;
  45. try {
  46. workDir = File.createTempFile("hadoop-unjar", "", tmpDir);
  47. } catch (IOException ioe) {
  48. // If user has insufficient perms to write to tmpDir, default
  49. // "Permission denied" message doesn't specify a filename.
  50. System.err.println("Error creating temp dir in hadoop.tmp.dir "
  51. + tmpDir + " due to " + ioe.getMessage());
  52. System.exit(-1);
  53. return;
  54. }
  55.  
  56. if (!workDir.delete()) {
  57. System.err.println("Delete failed for " + workDir);
  58. System.exit(-1);
  59. }
  60. ensureDirectory(workDir);
  61. //增加删除工作目录的钩子,任务执行完后要删除
  62. ShutdownHookManager.get().addShutdownHook(
  63. new Runnable() {
  64. @Override
  65. public void run() {
  66. FileUtil.fullyDelete(workDir);
  67. }
  68. }, SHUTDOWN_HOOK_PRIORITY);
  69.  
  70. unJar(file, workDir);
  71.  
  72. ArrayList<URL> classPath = new ArrayList<URL>();
  73. classPath.add(new File(workDir+"/").toURI().toURL());
  74. classPath.add(file.toURI().toURL());
  75. classPath.add(new File(workDir, "classes/").toURI().toURL());
  76. File[] libs = new File(workDir, "lib").listFiles();
  77. if (libs != null) {
  78. for (int i = 0; i < libs.length; i++) {
  79. classPath.add(libs[i].toURI().toURL());
  80. }
  81. }
  82. //通过反射的方式执行任务程序的main方法,并把剩余的参数作为任务程序main方法的参数
  83. ClassLoader loader =
  84. new URLClassLoader(classPath.toArray(new URL[0]));
  85.  
  86. Thread.currentThread().setContextClassLoader(loader);
  87. Class<?> mainClass = Class.forName(mainClassName, true, loader);
  88. Method main = mainClass.getMethod("main", new Class[] {
  89. Array.newInstance(String.class, 0).getClass()
  90. });
  91. String[] newArgs = Arrays.asList(args)
  92. .subList(firstArg, args.length).toArray(new String[0]);
  93. try {
  94. main.invoke(null, new Object[] { newArgs });
  95. } catch (InvocationTargetException e) {
  96. throw e.getTargetException();
  97. }
  98. }

环境设置好后就要开始执行任务程序的main方法了
以WordCount为例:

  1. package org.apache.hadoop.examples;
  2.  
  3. import java.io.IOException;
  4. import java.util.StringTokenizer;
  5.  
  6. import org.apache.hadoop.conf.Configuration;
  7. import org.apache.hadoop.fs.Path;
  8. import org.apache.hadoop.io.IntWritable;
  9. import org.apache.hadoop.io.Text;
  10. import org.apache.hadoop.mapreduce.Job;
  11. import org.apache.hadoop.mapreduce.Mapper;
  12. import org.apache.hadoop.mapreduce.Reducer;
  13. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  14. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  15. import org.apache.hadoop.util.GenericOptionsParser;
  16.  
  17. public class WordCount {
  18.  
  19. public static class TokenizerMapper
  20. extends Mapper<Object, Text, Text, IntWritable>{
  21.  
  22. private final static IntWritable one = new IntWritable(1);
  23. private Text word = new Text();
  24.  
  25. public void map(Object key, Text value, Context context
  26. ) throws IOException, InterruptedException {
  27. StringTokenizer itr = new StringTokenizer(value.toString());
  28. while (itr.hasMoreTokens()) {
  29. word.set(itr.nextToken());
  30. context.write(word, one);
  31. }
  32. }
  33. }
  34.  
  35. public static class IntSumReducer
  36. extends Reducer<Text,IntWritable,Text,IntWritable> {
  37. private IntWritable result = new IntWritable();
  38.  
  39. public void reduce(Text key, Iterable<IntWritable> values,
  40. Context context
  41. ) throws IOException, InterruptedException {
  42. int sum = 0;
  43. for (IntWritable val : values) {
  44. sum += val.get();
  45. }
  46. result.set(sum);
  47. context.write(key, result);
  48. }
  49. }
  50.  
  51. public static void main(String[] args) throws Exception {
  52. Configuration conf = new Configuration();
  53. String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
  54. if (otherArgs.length != 2) {
  55. System.err.println("Usage: wordcount <in> <out>");
  56. System.exit(2);
  57. }
  58. Job job = new Job(conf, "word count");
  59. job.setJarByClass(WordCount.class);
  60. job.setMapperClass(TokenizerMapper.class);
  61. job.setCombinerClass(IntSumReducer.class);
  62. job.setReducerClass(IntSumReducer.class);
  63. job.setOutputKeyClass(Text.class);
  64. job.setOutputValueClass(IntWritable.class);
  65. FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
  66. FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
  67. System.exit(job.waitForCompletion(true) ? 0 : 1);
  68. }
  69. }

在程序运行入口main方法中

首先定义配置文件类 Configuration,此类是Hadoop各个模块的公共使用类,用于加载类路径下的各种配置文件,读写其中的配置选项;

第二步中用到了 GenericOptionsParser 类,其目的是将命令行中的后部分参数自动设置到变量conf中,

如果代码提交的时候传入其他参数,比如指定reduce的个数,可以根据 GenericOptionsParser的命令行格式这么写:

bin/hadoop jar MyJob.jar com.xxx.MyJobDriver -Dmapred.reduce.tasks=5,

其规则是 -D 加上MR的配置选项(默认reduce task的个数为1,map的个数也为1);


之后就是 Job 的定义

使用的job类的构造方法为

  1. public Job(Configuration conf, String jobName) throws IOException {
  2. this(conf);
  3. setJobName(jobName);
  4. }

调用了另外一个构造方法,并设置了Job的名字(即WordCount)

  1. public Job(Configuration conf) throws IOException {
  2. this(new JobConf(conf));
  3. }
  1. public JobConf(Configuration conf) {
  2. super(conf);
  3.  
  4. if (conf instanceof JobConf) {
  5. JobConf that = (JobConf)conf;
  6. credentials = that.credentials;
  7. }
  8.  
  9. checkAndWarnDeprecation();
  10. }

job 已经根据 配置信息实例化好运行环境了,下面就是加入实体“口食”

依次给job添加Jar包、设置Mapper类、设置合并类、设置Reducer类、设置输出键类型、设置输出值类型

在setJarByClass中

  1. public void setJarByClass(Class<?> cls) {
  2. ensureState(JobState.DEFINE);
  3. conf.setJarByClass(cls);
  4. }

它先判断当前job的状态是否在运行中,接着通过class找到jar文件,将jar路径赋值给mapreduce.jar.jar属性(寻找jar文件的方法使通过ClassUtil类中的findContainingJar方法)


job的提交方法是

  1. job.waitForCompletion(true)
  1. public boolean waitForCompletion(boolean verbose
  2. ) throws IOException, InterruptedException,
  3. ClassNotFoundException {
  4. if (state == JobState.DEFINE) {
  5. submit();
  6. }
  7. if (verbose) {
  8. monitorAndPrintJob();
  9. } else {
  10. // get the completion poll interval from the client.
  11. int completionPollIntervalMillis =
  12. Job.getCompletionPollInterval(cluster.getConf());
  13. while (!isComplete()) {
  14. try {
  15. Thread.sleep(completionPollIntervalMillis);
  16. } catch (InterruptedException ie) {
  17. }
  18. }
  19. }
  20. return isSuccessful();
  21. }

参数 verbose ,如果想在控制台打印当前的任务执行进度,则设为true


  1. public void submit()
  2. throws IOException, InterruptedException, ClassNotFoundException {
  3. ensureState(JobState.DEFINE);
  4. setUseNewAPI();
  5. connect();
  6. final JobSubmitter submitter =
  7. getJobSubmitter(cluster.getFileSystem(), cluster.getClient());
  8. status = ugi.doAs(new PrivilegedExceptionAction<JobStatus>() {
  9. public JobStatus run() throws IOException, InterruptedException,
  10. ClassNotFoundException {
  11. return submitter.submitJobInternal(Job.this, cluster);
  12. }
  13. });
  14. state = JobState.RUNNING;
  15. LOG.info("The url to track the job: " + getTrackingURL());
  16. }

在submit 方法中会把Job提交给对应的Cluster,然后不等待Job执行结束就立刻返回

同时会把Job实例的状态设置为JobState.RUNNING,从而来表示Job正在进行中

然后在Job运行过程中,可以调用getJobState()来获取Job的运行状态

Submit主要进行如下操作

  • 检查Job的输入输出是各项参数,获取配置信息和远程主机的地址,生成JobID,确定所需工作目录(也是MRAppMaster.java所在目录),执行期间设置必要的信息
  • 拷贝所需要的Jar文件和配置文件信息到HDFS系统上的指定工作目录,以便各个节点调用使用
  • 计算并获数去输入分片(Input Split)的数目,以确定map的个数
  • 调用YARNRunner类下的submitJob()函数,提交Job,传出相应的所需参数(例如 JobID等)。
  • 等待submit()执行返回Job执行状态,最后删除相应的工作目录。

在提交前先链接集群(cluster),通过connect方法

  1. private synchronized void connect()
  2. throws IOException, InterruptedException, ClassNotFoundException {
  3. if (cluster == null) {
  4. cluster =
  5. ugi.doAs(new PrivilegedExceptionAction<Cluster>() {
  6. public Cluster run()
  7. throws IOException, InterruptedException,
  8. ClassNotFoundException {
  9. return new Cluster(getConfiguration());
  10. }
  11. });
  12. }
  13. }

这是一个线程保护方法。这个方法中根据配置信息初始化了一个Cluster对象,即代表集群

  1. public Cluster(Configuration conf) throws IOException {
  2. this(null, conf);
  3. }
  4.  
  5. public Cluster(InetSocketAddress jobTrackAddr, Configuration conf)
  6. throws IOException {
  7. this.conf = conf;
  8. this.ugi = UserGroupInformation.getCurrentUser();
  9. initialize(jobTrackAddr, conf);
  10. }
  11.  
  12. private void initialize(InetSocketAddress jobTrackAddr, Configuration conf)
  13. throws IOException {
  14.  
  15. synchronized (frameworkLoader) {
  16. for (ClientProtocolProvider provider : frameworkLoader) {
  17. LOG.debug("Trying ClientProtocolProvider : "
  18. + provider.getClass().getName());
  19. ClientProtocol clientProtocol = null;
  20. try {
  21. if (jobTrackAddr == null) {
             //创建YARNRunner对象  
  22. clientProtocol = provider.create(conf);
  23. } else {
  24. clientProtocol = provider.create(jobTrackAddr, conf);
  25. }
  26. //初始化Cluster内部成员变量
  27. if (clientProtocol != null) {
  28. clientProtocolProvider = provider;
  29. client = clientProtocol;
  30. LOG.debug("Picked " + provider.getClass().getName()
  31. + " as the ClientProtocolProvider");
  32. break;
  33. }
  34. else {
  35. LOG.debug("Cannot pick " + provider.getClass().getName()
  36. + " as the ClientProtocolProvider - returned null protocol");
  37. }
  38. }
  39. catch (Exception e) {
  40. LOG.info("Failed to use " + provider.getClass().getName()
  41. + " due to error: " + e.getMessage());
  42. }
  43. }
  44. }
  45.  
  46. if (null == clientProtocolProvider || null == client) {
  47. throw new IOException(
  48. "Cannot initialize Cluster. Please check your configuration for "
  49. + MRConfig.FRAMEWORK_NAME
  50. + " and the correspond server addresses.");
  51. }
  52. }

可以看出创建客户端代理阶段使用了java.util.ServiceLoader,在2.3.0版本中包含LocalClientProtocolProvider(本地作业)和YarnClientProtocolProvider(yarn作业)(hadoop有一个Yarn参数mapreduce.framework.name用来控制你选择的应用框架。在MRv2里,mapreduce.framework.name有两个值:local和yarn),此处会根据mapreduce.framework.name的配置创建相应的客户端

(ServiceLoader是服务加载类,它根据文件配置来在java classpath环境中加载对应接口的实现类)

这里在实际生产中一般都是yarn,所以会创建一个YARNRunner对象(客户端代理类)类进行任务的提交


实例化Cluster后开始真正的任务提交

  1. submitter.submitJobInternal(Job.this, cluster)
  1. JobStatus submitJobInternal(Job job, Cluster cluster)
  2. throws ClassNotFoundException, InterruptedException, IOException {
  3.  
  4. //检测输出目录合法性,是否已存在,或未设置
  5. checkSpecs(job);
  6.  
  7. Configuration conf = job.getConfiguration();
  8. addMRFrameworkToDistributedCache(conf);
  9. //获得登录区,用以存放作业执行过程中用到的文件,默认位置/tmp/hadoop-yarn/staging/root/.staging ,可通过yarn.app.mapreduce.am.staging-dir修改
  10. Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);
  11. //主机名和地址设置
  12. InetAddress ip = InetAddress.getLocalHost();
  13. if (ip != null) {
  14. submitHostAddress = ip.getHostAddress();
  15. submitHostName = ip.getHostName();
  16. conf.set(MRJobConfig.JOB_SUBMITHOST,submitHostName);
  17. conf.set(MRJobConfig.JOB_SUBMITHOSTADDR,submitHostAddress);
  18. }
  19. //获取新的JobID,此处需要RPC调用
  20. JobID jobId = submitClient.getNewJobID();
  21. job.setJobID(jobId);
  22. //获取提交目录:/tmp/hadoop-yarn/staging/root/.staging/job_1395778831382_0002
  23. Path submitJobDir = new Path(jobStagingArea, jobId.toString());
  24. JobStatus status = null;
  25. try {
  26. conf.set(MRJobConfig.USER_NAME,
  27. UserGroupInformation.getCurrentUser().getShortUserName());
  28. conf.set("hadoop.http.filter.initializers",
  29. "org.apache.hadoop.yarn.server.webproxy.amfilter.AmFilterInitializer");
  30. conf.set(MRJobConfig.MAPREDUCE_JOB_DIR, submitJobDir.toString());
  31. LOG.debug("Configuring job " + jobId + " with " + submitJobDir
  32. + " as the submit dir");
  33. // get delegation token for the dir
  34. TokenCache.obtainTokensForNamenodes(job.getCredentials(),
  35. new Path[] { submitJobDir }, conf);
  36.  
  37. populateTokenCache(conf, job.getCredentials());
  38.  
  39. // generate a secret to authenticate shuffle transfers
  40. if (TokenCache.getShuffleSecretKey(job.getCredentials()) == null) {
  41. KeyGenerator keyGen;
  42. try {
  43. keyGen = KeyGenerator.getInstance(SHUFFLE_KEYGEN_ALGORITHM);
  44. keyGen.init(SHUFFLE_KEY_LENGTH);
  45. } catch (NoSuchAlgorithmException e) {
  46. throw new IOException("Error generating shuffle secret key", e);
  47. }
  48. SecretKey shuffleKey = keyGen.generateKey();
  49. TokenCache.setShuffleSecretKey(shuffleKey.getEncoded(),
  50. job.getCredentials());
  51. }
  52. //向集群中拷贝所需文件,下面会单独分析(1)
  53. copyAndConfigureFiles(job, submitJobDir);
  54. Path submitJobFile = JobSubmissionFiles.getJobConfPath(submitJobDir);
  55.  
  56. // 写分片文件job.split job.splitmetainfo,具体写入过程与MR1相同,可参考以前文章
  57. LOG.debug("Creating splits at " + jtFs.makeQualified(submitJobDir));
  58. int maps = writeSplits(job, submitJobDir);
  59. conf.setInt(MRJobConfig.NUM_MAPS, maps);
  60. LOG.info("number of splits:" + maps);
  61.  
  62. // write "queue admins of the queue to which job is being submitted"
  63. // to job file.
  64. //设置队列名
  65. String queue = conf.get(MRJobConfig.QUEUE_NAME,
  66. JobConf.DEFAULT_QUEUE_NAME);
  67. AccessControlList acl = submitClient.getQueueAdmins(queue);
  68. conf.set(toFullPropertyName(queue,
  69. QueueACL.ADMINISTER_JOBS.getAclName()), acl.getAclString());
  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(conf);
  76.  
  77. if (conf.getBoolean(
  78. MRJobConfig.JOB_TOKEN_TRACKING_IDS_ENABLED,
  79. MRJobConfig.DEFAULT_JOB_TOKEN_TRACKING_IDS_ENABLED)) {
  80. // Add HDFS tracking ids
  81. ArrayList<String> trackingIds = new ArrayList<String>();
  82. for (Token<? extends TokenIdentifier> t :
  83. job.getCredentials().getAllTokens()) {
  84. trackingIds.add(t.decodeIdentifier().getTrackingId());
  85. }
  86. conf.setStrings(MRJobConfig.JOB_TOKEN_TRACKING_IDS,
  87. trackingIds.toArray(new String[trackingIds.size()]));
  88. }
  89.  
  90. // Write job file to submit dir
  91. //写入job.xml
  92. writeConf(conf, submitJobFile);
  93.  
  94. //
  95. // Now, actually submit the job (using the submit name)
  96. //这里才开始真正提交,见下面分析(2)
  97. printTokens(jobId, job.getCredentials());
  98. status = submitClient.submitJob(
  99. jobId, submitJobDir.toString(), job.getCredentials());
  100. if (status != null) {
  101. return status;
  102. } else {
  103. throw new IOException("Could not launch job");
  104. }
  105. } finally {
  106. if (status == null) {
  107. LOG.info("Cleaning up the staging area " + submitJobDir);
  108. if (jtFs != null && submitJobDir != null)
  109. jtFs.delete(submitJobDir, true);
  110.  
  111. }
  112. }
  113. }

洋洋洒洒一百余行
(这个可谓任务提交的核心部分,前面的都是铺垫)

Step1:
检查job的输出路径是否存在,如果存在则抛出异常。
Step2:
初始化用于存放Job相关资源的路径。
Step3:
设置客户端的host属性:mapreduce.job.submithostname和mapreduce.job.submithostaddress。
Step4:
通过RPC,向Yarn的ResourceManager申请JobID对象。
Step5:
从HDFS的NameNode获取验证用的Token,并将其放入缓存。
Step6:
将作业文件上传到HDFS,这里如果我们前面没有对Job命名的话,默认的名称就会在这里设置成jar的名字。并且,作业默认的副本数是10,如果属性mapreduce.client.submit.file.replication没有被设置的话。
Step7:
文件上传到HDFS之后,还要被DistributedCache进行缓存起来。这是因为计算节点收到该作业的第一个任务后,就会有DistributedCache自动将作业文件Cache到节点本地目录下,并且会对压缩文件进行解压,如:.zip,.jar,.tar等等,然后开始任务。
最后,对于同一个计算节点接下来收到的任务,DistributedCache不会重复去下载作业文件,而是直接运行任务。如果一个作业的任务数很多,这种设计避免了在同一个节点上对用一个job的文件会下载多次,大大提高了任务运行的效率。
Step8:
对每个输入文件进行split划分。
关于split的分片:http://www.cnblogs.com/admln/p/hadoop-mapper-numbers-question.html
Step9:
将split信息和SplitMetaInfo都写入HDFS中
Step10:
对Map数目设置,上面获得到的split的个数就是实际的Map任务的数目。
Step11:
相关配置写入到job.xml中
Step12:
(可以看出目标文件的切分上传、任务ID的申请、合法性检查、map数量的计算等等都是在提交到yarn之前搞定的,yarn只管根据任务申请资源并调度执行)
通过如下代码正式提交Job到Yarn:
  1. status = submitClient.submitJob( jobId, submitJobDir.toString(), job.getCredentials());

这里就涉及到YarnClient和RresourceManager的RPC通信了。包括获取applicationId、进行状态检查、网络通信等

这里的submitClient其实就是 YARNRunner的实体类了;

Step13:
上面通过RPC的调用,最后会返回一个JobStatus对象,它的toString方法可以在JobClient端打印运行的相关日志信息。
(到这里任务都给yarn了,这里就只剩下监控(如果设置为true的话))
  1. monitorAndPrintJob();

这只是粗略的job提交,详细的还有从在yarn上的RPC通信、在datanode上从文件的输入到map的执行、经过shuffle过程、reduce的执行最后结果的写文件


MR任务的提交大多是任务环境的初始化过程,任务的执行则大多涉及到任务的调度


hadoop2 作业执行过程之作业提交的更多相关文章

  1. hadoop2 作业执行过程之map过程

    在执行MAP任务之前,先了解一下它的容器和它容器的领导:container和nodemanager NodeManager NodeManager(NM)是YARN中每个节点上的代理,它管理Hadoo ...

  2. hadoop2 作业执行过程之yarn调度执行

    YARN是hadoop系统上的资源统一管理平台,其主要作用是实现集群资源的统一管理和调度(目前还不完善,只支持粗粒度的CPU和内存的的调配): 它的基本思想是将Mapreduce的jobtracker ...

  3. hadoop2 作业执行过程之reduce过程

    reduce阶段就是处理map的输出数据,大部分过程和map差不多 //ReduceTask.run方法开始和MapTask类似,包括initialize()初始化,根据情况看是否调用runJobCl ...

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

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

  5. MapReduce调度与执行原理之作业初始化

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

  6. spark作业运行过程之--DAGScheduler

    DAGScheduler--stage划分和创建以及stage的提交 本篇,我会从一次spark作业的运行为切入点,将spark运行过程中涉及到的各个步骤,包括DAG图的划分,任务集的创建,资源分配, ...

  7. Spark作业执行

    Spark中一个action触发一个job的执行,在job提交过程中主要涉及Driver和Executor两个节点. Driver主要解决 1. RDD 依赖性分析,生成DAG. 2. 根据RDD D ...

  8. SQL Server2005作业执行失败的解决办法

    数据库:SQL Server 2005,运行环境:Windows Server 2008  在数据库里的所有作业都执行失败,包括自动执行和手动执行.在事件查看器里看到的错误报告如下: 该作业失败.  ...

  9. SQlServer2008 之 定时执行sql语句作业的制定

    1.打开[SQL Server Management Studio],在[对象资源管理器]列表中选择[SQL Server 代理]: 2.鼠标右击[SQL Server 代理],选择[启动(S)],如 ...

随机推荐

  1. openstack-dbs

    真正的服务器派生出线程 和子进程处理多个连接当允许客户端加入聊天室,他发送的任何一条文本都将广播给聊天室中的每个用户,除非文本是服务器CLI当广播一条消息,消息前面将加上发送者的昵称 以尖括号括住昵称 ...

  2. SharePoint咨询师之路:设计之前的那些事四:负载均衡 - web服务器

     提示:本系列只是一个学习笔记系列,大部分内容都可以从微软官方网站找到,本人只是按照自己的学习路径来学习和呈现这些知识.有些内容是自己的经验和积累,如果有不当之处,请指正. 容量管理 规模 体系结构 ...

  3. JXTA+JavaFX实现的网络黑白棋测试地址

    http://www.qhdbaobao.com/dist/secondegg-reversi.html ——————————————————————————————————————————————— ...

  4. 异步编程之Generator(1)——领略魅力

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  5. U盘FAT32文件系统

    一.FAT文件系统分为四个部分 参考别人的博客 1.http://blog.163.com/ourhappines@126/blog/static/121363154201311811495492/ ...

  6. hdoj 5375 Gray Code

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5375 编码规则:tmp = XOR(gr[i],gr[i-1]); 算是找规律的题目吧,考虑?前后字符 ...

  7. 结构类模式(一):适配器(Adapter)

    定义 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 类适配器模式 使用继承的方式实现没有提供的接口从而达到适配到新系统的需求. ...

  8. 第一章TP-Link 703N刷OpenWrt

    1)下载编译好的固件 openwrt-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin openwrt-ar71xx-generic-tl-wr703n ...

  9. 使用 EasyMock 更轻松地进行测试

    from:http://www.ibm.com/developerworks/cn/java/j-easymock.html 测试驱动开发是软件开发的重要部分.如果代码不进行测试,就是不可靠的.所有代 ...

  10. props 和 state的区别

    作者:孙志勇 微博 日期:2016年11月29日 一.时效性 所有信息都具有时效性.文章的价值,往往跟时间有很大关联.特别是技术类文章,请注意本文创建时间,如果本文过于久远,请读者酌情考量,莫要浪费时 ...