您现在的位置 >> Hadoop教程 >> Hadoop实战 >> hadoop专题  
 

hadoop作业提交脚本分析(1)

【作者:Hadoop实战专家】【关键词:解压 hadoop 】 【点击:58404次】【2013-11-0】
通过对上面的分析,我们知道了,如果想取代这个脚本,那就必须至少把Hadoop依赖的库和配置文件目录给加到CLASSPATH中(JAVA_HEAP_MAX和HADOOP_OPTS不是必须的),然后调用org.apache.hadoop.util.RunJar类来提交Jar到Hadoop。  

相关热门搜索:

大数据标签:hadoop hdfs hive bigdata

阅读本文可以带着下面问题:
1.哪一个参数才是最终真正执行你的命令的实体?
2.RunJar的作用是什么?

我们首先从bin/hadoop这个Shell脚本开始分析,看这个脚本内部到底做了什么,如何来提交Hadoop作业的。

因为是Java程序,这个脚本最终都是要调用Java来运行的,所以这个脚本最重要的就是添加一些前置参数,如CLASSPATH等。所以,我们直接跳到这个脚本的最后一行,看它到底添加了那些参数,然后再逐个分析(本文忽略了脚本中配置环境参数载入、Java查找、cygwin处理等的分析)。

1. # run it

2. exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"

复制代码
从上面这行命令我们可以看到这个脚本最终添加了如下几个重要参数:JAVA_HEAP_MAX、HADOOP_OPTS、CLASSPATH、CLASS。下面我们来一个个的分析(本文基于Cloudera Hadoop 0.20.1+152分析)。

  首先是JAVA_HEAP_MAX,这个就比较简单了,主要涉及代码如下:

1. JAVA_HEAP_MAX=-Xmx1000m

2. # check envvars which might override default args

3. if [ "$HADOOP_HEAPSIZE" != "" ]; then

4.   #echo "run with heapsize $HADOOP_HEAPSIZE"

5.   JAVA_HEAP_MAX="-Xmx""$HADOOP_HEAPSIZE""m"

6.   #echo $JAVA_HEAP_MAX

7. fi

复制代码
首先赋予默认值-Xmx1000m,然后检查hadoop-env.sh中是否设置并导出了HADOOP_HEAPSIZE,如果有的话,就使用该值覆盖,得到最后的JAVA_HEAP_MAX。

  接着是分析CLASSPATH,这是这个脚本的重点之一。这部分主要就是添加了相应依赖库和配置文件到CLASSPATH。

1. # 首先用Hadoop的配置文件目录初始化CLASSPATH

2. CLASSPATH="${HADOOP_CONF_DIR}"

3. ……

4. # 下面是针对于Hadoop发行版,添加Hadoop核心Jar包和webapps到CLASSPATH

5. if [ -d "$HADOOP_HOME/webapps" ]; then

6.   CLASSPATH=${CLASSPATH}:$HADOOP_HOME

7. fi

8. for f in $HADOOP_HOME/hadoop-*-core.jar; do

9.   CLASSPATH=${CLASSPATH}:$f;

10. done

11. # 添加libs里的Jar包

12. for f in $HADOOP_HOME/lib/*.jar; do

13.   CLASSPATH=${CLASSPATH}:$f;

14. Done

15. for f in $HADOOP_HOME/lib/jsp-2.1/*.jar; do

16.   CLASSPATH=${CLASSPATH}:$f;

17. done

18. # 下面的TOOL_PATH只在命令为“archive”时才添加到CLASSPATH

19. for f in $HADOOP_HOME/hadoop-*-tools.jar; do

20.   TOOL_PATH=${TOOL_PATH}:$f;

21. done

22. for f in $HADOOP_HOME/build/hadoop-*-tools.jar; do

23.   TOOL_PATH=${TOOL_PATH}:$f;

24. done

25. # 最后添加用户的自定义Hadoop Classpath

26. if [ "$HADOOP_CLASSPATH" != "" ]; then

27.   CLASSPATH=${CLASSPATH}:${HADOOP_CLASSPATH}

28. fi

复制代码
上面只分析一部分,由于代码比较长,针对开发者部分的CLASSPATH添加没有列出来。

  下面是这个脚本的重点、实体之处:CLASS分析。Shell脚本会根据你输入的命令参数来设置CLASS和HADOOP_OPTS,其中CLASS所指向的类才是最终真正执行你的命令的实体。

1. # figure out which class to run

2. if [ "$COMMAND" = "namenode" ] ; then

3.   CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'

4.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS"

5. ……

6. elif [ "$COMMAND" = "fs" ] ; then

7.   CLASS=org.apache.hadoop.fs.FsShell

8.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"

9. ……

10. elif [ "$COMMAND" = "jar" ] ; then

11.   CLASS=org.apache.hadoop.util.RunJar

12. ……

13. elif [ "$COMMAND" = "archive" ] ; then

14.   CLASS=org.apache.hadoop.tools.HadoopArchives

15.   CLASSPATH=${CLASSPATH}:${TOOL_PATH}

16.   HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"

17. ……

18. else

19.   CLASS=$COMMAND

20. fi

复制代码
这里我们要关心的就是"$COMMAND" = "jar"时对应的类org.apache.hadoop.util.RunJar,这个类等下我们继续分析,这是我们通向最终目标的下一个路口。

  脚本在最后还设置了hadoop.log.dir、hadoop.log.file等HADOOP_OPTS。接着,就利用exec命令带上刚才的参数提交任务了。

  通过对上面的分析,我们知道了,如果想取代这个脚本,那就必须至少把Hadoop依赖的库和配置文件目录给加到CLASSPATH中(JAVA_HEAP_MAX和HADOOP_OPTS不是必须的),然后调用org.apache.hadoop.util.RunJar类来提交Jar到Hadoop。

--------------------------------------------------------------------------------------------------------------------------

上面我们分析了bin/hadoop脚本,知道了提交一个Hadoop作业所需要的基本设置以及真正执行任务提交的类。下面我们就来分析这个提交任务的类org.apache.hadoop.util.RunJar,看它内部具体又做了些什么。

RunJar是Hadoop中的一个工具类,结构很简单,只有两个方法:main和unJar。我们从main开始一步步分析。

main首先检查传递参数是否符合要求,然后从第一个传递参数中获取jar包的名字,并试图从jar中包中获取manifest信息,以查找mainclass name。如果查找不到mainclass name,则把传递参数中的第二个设为mainclass name。

接下去,就是在"hadoop.tmp.dir"下创建一个临时文件夹,并挂载上关闭删除线程。这个临时文件夹用来放置解压后的jar包内容。jar包的解压工作由unJar方法完成,通过JarEntry逐个获取jar包内的内容,包括文件夹和文件,然后释放到临时文件夹中。

解压完毕后,开始做classpath的添加,依次把解压临时文件夹、传递进来的jar包、临时文件夹内的classes文件夹和lib里的所有jar包加入到classpath中。接着以这个classpath为搜索URL新建了一个URLClassLoader(要注意这个类加载器的parent包括了刚才bin/hadoop脚本提交时给的classpath),并设置为当前线程的上下文类加载器。

最后,利用Class.forName方法,以刚才的那个URLClassLoader为类加载器,动态生成一个mainclass的Class对象,并获取它的main方法,然后以传递参数中剩下的参数作为调用参数来调用这个main方法。

好了,从上分析看来,这个RunJar类是一个很简单的类,就是解压传递进来的jar包,再添加一些classpath,然后动态调用jar包里的mainclass的main方法。看到这里,我想你应该知道如何利用java代码来编写一个替代bin/hadoop的程序了,主要就是两步:

* 添加Hadoop的依赖库和配置文件;
* 解压jar包,再添加一些classpath,并动态调用相应方法。最偷懒的方法,直接用RunJar类就行了。

大数据系列hadoop相关文章:

最新评论
兔妹子2014-09-10 08:05:58
杨俊林加入本群
Sandy2014-09-09 06:06:57
我运行start-all.sh
周亮2014-09-08 08:21:03
一次性可以提交多个相互独立的作业吗?
小墨怡2014-09-07 11:00:40
0
我是谁2014-09-07 12:58:38
[图片]
诺言蜚语2014-09-06 07:58:44
早期,Linus做Linux的时候确实是集市模式,做得很不错!不过Linux后来的发展,却几乎被Red Hat、Novell和Canonical等公司把控。Hadoop最先是Lucene子项目,发起者是大名鼎鼎的Doug Cutting,他连续发起了Lucene、Nutch和Hadoop。名气再大也要穿衣吃饭,他现在的角色是什么呢:Cloudera的首席架构师!
灰太狼2014-09-05 10:32:28
《大数据》HBase是一个开源的非关系型数据库,它基于Google提出的BigTable建模并使用Java进行实现,它也是Hadoop项目的一部分。因为基于HDFS,HBase的性能非常好。目前它最常见的应用场景是存储海量的结构化数据以及非结构化数据。
人在旅途2014-09-04 07:37:43
你看外国的什么都开源
海岸线2014-09-04 04:37:38
【惠普5000万美元战略投资大数据平台Hortonworks】北京时间7月25日消息,据科技博客ReCode报道,惠普即将宣布对大数据平台Hortonworks战略投资5000万美元。Hortonworks是2011年从雅虎分拆出来的Hadoop创业公司。 http://t.cn/RPG6VsC
大脸妹20122014-09-04 02:17:59
给hadoop新手的一封信:Hadoop入门自学及对就业的帮助-小象科技|专业于Hadoop培训及大数据技术平台、数据分析、数据挖掘、数据可视化的技术服务创新型科技公司 - http://t.cn/RPL21Cg
 
  • Hadoop生态系统资料推荐