Hadoop1.X,Hadoop2.X源码编译与调试汇总
本帖最后由 pig2 于 2014-5-6 04:28 编辑虽然在运行Hadoop的时候可以打印出大量的运行日志,但是很多时候只通过打印这些日志是不能很好地跟踪Hadoop各个模块的运行状况。这时候编译与调试Hadoop源码就得派上场了。这也就是今天本文需要讨论的。
先说说怎么编译Hadoop源码,本文主要介绍在Linux环境下用Maven来编译Hadoop。在编译Hadoop之前,我们需要准备好编译环境:
1、安装好1.6或以上的JDK;
2、安装Maven,被做好相应的配置;
3、安装ProtocolBuffer 2.5.0,MapReduce和HDFS用google protocol buffer来压缩和交换数据;
4、如果你是第一次编译,则需要保证电脑能够网络连接,主要用于获取所有Maven和Hadoop依赖库;
5、如果你需要查找bug,则需要安装Findbugs;
6、如果要生成文档则需要安装Forrest 0.8;
7、如果编译native code则需要安装Autoto;
上面的前提条件1-4是必须的,5-7是可选的。编译的环境准备好之后,那我们就可以去编译Hadoop源码了。本文以编译Hadoop2.2.0源码为例,进行说明。从官方下载下来的Hadoop源码一般是包含以下几个Maven工程:
hadoop-assemblies
hadoop-client
hadoop-common-project
hadoop-dist
hadoop-hdfs-project
hadoop-mapreduce-project
hadoop-maven-plugins
hadoop-minicluster
hadoop-project
hadoop-project-dist
hadoop-tools
hadoop-yarn-project上面各个功能模块的含义已经超出本文的主题,所以我不打算介绍。将上面的源码放在一个地方,比如,我放在/home/wyp/hadoop文件夹中,下面提供几种Hadoop源码的编译方式及说明如果不需要native code、忽略测试用例和文档,可以用下面的命令创建二进制分发版:
$ mvn package -Pdist -DskipTests -Dtar
创建二进制分发版,带native code和文档:
$ mvn package -Pdist,native,docs -DskipTests -Dtar
创建源码分发版
$ mvn package -Psrc -DskipTests
创建二进制带源码分发版,带native code和文档:
$ mvn package \
-Pdist,native,docs,src -DskipTests -Dtar
创建本地版web页面,放在/tmp/hadoop-site
$ mvn clean site; mvn \
site:stage -DstagingDirectory=/tmp/hadoop-site上面提供了几种Hadoop源码的编译方式(参考文档:http://svn.apache.org/repos/asf/hadoop/common/trunk/BUILDING.txt),大家可以根据自己的需求选择不同的编译方式,但是这里我推荐第一种编译方式。我们可以将编译好的模块覆盖掉${HADOOP_HOME} /share/hadoop目录中对应模块里面的jar文件,然后重启Hadoop集群则新的编译包将生效。 远程调试Hadoop 远程调试对应用程序开发十分有用,那如何调试Hadoop源码?这里介绍如何用IDE远程调试Hadoop源码。本文以IntelliJ IDEA作为IDE,以调试Jobhistory WEB UI代码为例进行说明。
第一步:在启动Hadoop历史服务器进程之前在终端加入以下环境配置:$ export HADOOP_OPTS="-Xdebug \
-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8888"这里对上面的几个参数进行说明:-Xdebug 启用调试特性-Xrunjdwp 启用JDWP实现,包含若干子选项:transport=dt_socket JPDA front-end和back-end之间的传输方法。dt_socket表示使用套接字传输。address=8888 JVM在8888端口上监听请求,这个设定为一个不冲突的端口即可。server=y y表示启动的JVM是被调试者。如果为n,则表示启动的JVM是调试器。suspend=y y表示启动的JVM会暂停等待,直到调试器连接上才继续执行。suspend=n,则JVM不会暂停等待。
第二步:启动Jobhistory进程$ ${HODOOP_HOME}/sbin/mr-jobhistory-daemon.sh\ start historyserver
starting historyserver, logging to /home/wyp/Downloads/\
hadoop/logs/mapred-wyp-historyserver-master.out
Listening for transport dt_socket at address: 8888上面的Listening for transport dt_socket at address: 8888表明jobhistory已经在端口为8888启动了远程调试。
第三步:打开IntelliJ IDEA,找到hadoop-2.2.0-src\hadoop-mapreduce-project\hadoop-mapreduce-client\hadoop-mapreduce-client-hs\src\main\java\org\apache\hadoop\mapreduce\v2\hs\webapp\HsController.java类,在里面设置一些断点,然后依次选择菜单 Run->Run…->Edit Configurations…->选择左上角的+号->Remote,这时右边将会出现一个Configuration页面进行远程调试配置,请在Host和Port文本框里面输入jobhistory服务所在主机的IP及刚刚的8888端口,然后选择OK。这时候IDE进入了远程调试模式,你可以和普通的调试一样调试Hadoop源码。调试其他的Hadoop源码道理和上面的一样,这里就不一一列举了。
本帖最后由 howtodown 于 2014-1-16 17:46 编辑
Hadoop2.2.0版本比Hadoop0.x或Hadoop1.x结构变化很大,而且也没有Eclipse-Hadoop插件支持.本文就Eclipse如何整合Hadoop2.2.0与自己实际操作步骤方法分享给大家,希望对大家有所帮助.JPDA 简介Sun Microsystem 的 Java Platform Debugger Architecture (JPDA) 技术是一个多层架构,使您能够在各种环境中轻松调试 Java 应用程序。JPDA 由两个接口(分别是 JVM Tool Interface 和 JDI)、一个协议(Java Debug Wire Protocol)和两个用于合并它们的软件组件(后端和前端)组成。它的设计目的是让调试人员在任何环境中都可以进行调试。JDWP 设置JVM本身就支持远程调试,Eclipse也支持JDWP,只需要在各模块的JVM启动时加载以下参数:-Xdebug -Xrunjdwp:transport=dt_socket, address=1221,server=y,suspend=y各参数的含义:-Xdebug
启用调试特性
-Xrunjdwp
启用JDWP实现,包含若干子选项:
transport=dt_socket
JPDA front-end和back-end之间的传输方法。dt_socket表示使用套接字传输。
address=8000
JVM在8000端口上监听请求,这个设定为一个不冲突的端口即可。
server=y
y表示启动的JVM是被调试者。如果为n,则表示启动的JVM是调试器。
suspend=y
y表示启动的JVM会暂停等待,直到调试器连接上才继续执行。suspend=n,则JVM不会暂停等待。配置mapreduce远程调试<property>
<name>mapred.child.java.opts</name>
<value>-Xmx800m -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1221</value>
</property>
<!– 在一个TT,只能启动一个MT或一个RT,否则启动时会有端口冲突 –>
<property>
<name>mapred.tasktracker.map.tasks.maximum</name>
<value>1</value>
</property>
<property>
<name>mapred.tasktracker.reduce.tasks.maximum</name>
<value>0</value>
</property>配置yarn远程调试export YARN_RESOURCEMANAGER_OPTS=”$YARN_RESOURCEMANAGER_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1222″
export YARN_NODEMANAGER_OPTS=”$YARN_RESOURCEMANAGER_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1223″ 本帖最后由 pig2 于 2014-1-16 17:42 编辑
在Eclipse中远程调试Hadoop插件话说Hadoop 1.0.2/src/contrib/eclipse-plugin只有插件的源代码,这里给出一个我打包好的对应的Eclipse插件:
下载地址下载后扔到eclipse/dropins目录下即可,当然eclipse/plugins也是可以的,前者更为轻便,推荐;重启Eclipse,即可在透视图(Perspective)中看到Map/Reduce。配置点击蓝色的小象图标,新建一个Hadoop连接:注意,一定要填写正确,修改了某些端口,以及默认运行的用户名等具体的设置,可见正常情况下,可以在项目区域可以看到这样可以正常的进行HDFS分布式文件系统的管理:上传,删除等操作。为下面测试做准备,需要先建了一个目录 user/root/input2,然后上传两个txt文件到此目录:intput1.txt 对应内容:Hello Hadoop Goodbye Hadoopintput2.txt 对应内容:Hello World Bye WorldHDFS的准备工作好了,下面可以开始测试了。Hadoop工程新建一个Map/Reduce Project工程,设定好本地的hadoop目录新建一个测试类WordCountTest:
package com.hadoop.learn.test;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.log4j.Logger;
/**
* 运行测试程序
*
* @author yongboy
* @date 2012-04-16
*/
public class WordCountTest {
private static final Logger log = Logger.getLogger(WordCountTest.class);
public static class TokenizerMapper extends
Mapper<Object, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context)
throws IOException, InterruptedException {
log.info("Map key : " + key);
log.info("Map value : " + value);
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
String wordStr = itr.nextToken();
word.set(wordStr);
log.info("Map word : " + wordStr);
context.write(word, one);
}
}
}
public static class IntSumReducer extends
Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
log.info("Reduce key : " + key);
log.info("Reduce value : " + values);
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
log.info("Reduce sum : " + sum);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf, args)
.getRemainingArgs();
if (otherArgs.length != 2) {
System.err.println("Usage: WordCountTest <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "word count");
job.setJarByClass(WordCountTest.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(otherArgs));
FileOutputFormat.setOutputPath(job, new Path(otherArgs));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}右键,选择“Run Configurations”,弹出窗口,点击“Arguments”选项卡,在“Program argumetns”处预先输入参数:
hdfs://master:9000/user/root/input2 dfs://master:9000/user/root/output2备注:参数为了在本地调试使用,而非真实环境。然后,点击“Apply”,然后“Close”。现在可以右键,选择“Run on Hadoop”,运行。但此时会出现类似异常信息:12/04/24 15:32:44 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
12/04/24 15:32:44 ERROR security.UserGroupInformation: PriviledgedActionException as:Administrator cause:java.io.IOException: Failed to set permissions of path: \tmp\hadoop-Administrator\mapred\staging\Administrator-519341271\.staging to 0700
Exception in thread "main" java.io.IOException: Failed to set permissions of path: \tmp\hadoop-Administrator\mapred\staging\Administrator-519341271\.staging to 0700
at org.apache.hadoop.fs.FileUtil.checkReturnValue(FileUtil.java:682)
at org.apache.hadoop.fs.FileUtil.setPermission(FileUtil.java:655)
at org.apache.hadoop.fs.RawLocalFileSystem.setPermission(RawLocalFileSystem.java:509)
at org.apache.hadoop.fs.RawLocalFileSystem.mkdirs(RawLocalFileSystem.java:344)
at org.apache.hadoop.fs.FilterFileSystem.mkdirs(FilterFileSystem.java:189)
at org.apache.hadoop.mapreduce.JobSubmissionFiles.getStagingDir(JobSubmissionFiles.java:116)
at org.apache.hadoop.mapred.JobClient$2.run(JobClient.java:856)
at org.apache.hadoop.mapred.JobClient$2.run(JobClient.java:850)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1093)
at org.apache.hadoop.mapred.JobClient.submitJobInternal(JobClient.java:850)
at org.apache.hadoop.mapreduce.Job.submit(Job.java:500)
at org.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:530)
at com.hadoop.learn.test.WordCountTest.main(WordCountTest.java:85)这个是Windows下文件权限问题,在Linux下可以正常运行,不存在这样的问题。解决方法是,修改/hadoop-1.0.2/src/core/org/apache/hadoop/fs/FileUtil.java里面的checkReturnValue,注释掉即可(有些粗暴,在Window下,可以不用检查):......
private static void checkReturnValue(boolean rv, File p,
FsPermission permission
) throws IOException {
/**
if (!rv) {
throw new IOException("Failed to set permissions of path: " + p +
" to " +
String.format("%04o", permission.toShort()));
}
**/
}
......重新编译打包hadoop-core-1.0.2.jar,替换掉hadoop-1.0.2根目录下的hadoop-core-1.0.2.jar即可。这里提供一份修改版的hadoop-core-1.0.2-modified.jar文件,替换原hadoop-core-1.0.2.jar即可。替换之后,刷新项目,设置好正确的jar包依赖,现在再运行WordCountTest,即可。成功之后,在Eclipse下刷新HDFS目录,可以看到生成了ouput2目录:点击“ part-r-00000”文件,可以看到排序结果:Bye 1
Goodbye 1
Hadoop 2
Hello 2
World 2嗯,一样可以正常Debug调试该程序,设置断点(右键 –> Debug As – > Java Application),即可(每次运行之前,都需要收到删除输出目录)。另外,该插件会在eclipse对应的workspace\.metadata\.plugins\org.apache.hadoop.eclipse下,自动生成jar文件,以及其他文件,包括Haoop的一些具体配置等。嗯,更多细节,慢慢体验吧。遇到的异常org.apache.hadoop.ipc.RemoteException: org.apache.hadoop.hdfs.server.namenode.SafeModeException: Cannot create directory /user/root/output2/_temporary. Name node is in safe mode.
The ratio of reported blocks 0.5000 has not reached the threshold 0.9990. Safe mode will be turned off automatically.
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.mkdirsInternal(FSNamesystem.java:2055)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.mkdirs(FSNamesystem.java:2029)
at org.apache.hadoop.hdfs.server.namenode.NameNode.mkdirs(NameNode.java:817)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:563)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1388)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1384)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1093)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:1382)在主节点处,关闭掉安全模式:#bin/hadoop dfsadmin –safemode leave如何打包将创建的Map/Reduce项目打包成jar包,很简单的事情,无需多言。保证jar文件的META-INF/MANIFEST.MF文件中存在Main-Class映射:Main-Class: com.hadoop.learn.test.TestDriver若使用到第三方jar包,那么在MANIFEST.MF中增加Class-Path好了。另外可使用插件提供的MapReduce Driver向导,可以帮忙我们在Hadoop中运行,直接指定别名,尤其是包含多个Map/Reduce作业时,很有用。一个MapReduce Driver只要包含一个main函数,指定别名:package com.hadoop.learn.test;
import org.apache.hadoop.util.ProgramDriver;
/**
*
* @author yongboy
* @time 2012-4-24
* @version 1.0
*/
public class TestDriver {
public static void main(String[] args) {
int exitCode = -1;
ProgramDriver pgd = new ProgramDriver();
try {
pgd.addClass("testcount", WordCountTest.class,
"A test map/reduce program that counts the words in the input files.");
pgd.driver(args);
exitCode = 0;
} catch (Throwable e) {
e.printStackTrace();
}
System.exit(exitCode);
}
}这里有一个小技巧,MapReduce Driver类上面,右键运行,Run on Hadoop,会在Eclipse的workspace\.metadata\.plugins\org.apache.hadoop.eclipse目录下自动生成jar包,上传到HDFS,或者远程hadoop根目录下,运行它:# bin/hadoop jar LearnHadoop_TestDriver.java-460881982912511899.jar testcount input2 output3到此完毕
本帖最后由 howtodown 于 2014-1-16 17:39 编辑
在eclipse下远程调试hadoop2.0
Hadoop是一个分布式系统基础架构,由apache基金会维护并更新。官网地址: http://hadoop.apache.org/
Hadoop项目主要包括以下4个模块:
[*]Hadoop Common: 为其他Hadoop模块提供基础设施。
[*]Hadoop HDFS: 一个高高靠、高吞吐量的分布式文件系统。
[*]Hadoop MapReduce: 一个分布式的计算框架,包括任务调度和集群资源管理。
[*]Hadoop YARN: 一个新的MapReduce框架。有兴趣的同学请参考: http://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-yarn/
由于项目的需要,我只需要用到Hadoop中的前两个子模块,即Hadoop Common和Hadoop HDFS。在编译源码之前,我先介绍一下我的开发环境:
[*]Ubuntu 12.04 LTS
[*]Eclipse 4.3
[*]JDK1.6.0_45
[*]Maven 3.0.4
[*]SVN1.6.17
[*]ProtocolBuffer(貌似Ubuntu自带了,如果没有,请自行下载安装)
最新的Hadoop采用maven作为项目构建工具,所以系统需要安装maven。下面正式开始Hadoop源码的编译之旅。首先用svn签出Hadoop的最新版本(hadoop 2.*):svn checkout http://svn.apache.org/repos/asf/hadoop/common/trunk/ hadoop-dev
打开hadoop-dev文件夹,目录结构如下图这就是Hadoop的源代码目录,顺便统计了一下源代码行数,1231074(包含注释、空行)。本文主要关心两个子项目,分别是hadoop-common-project、hadoop-hdfs-project。接下来就需要为导入Eclipse构建Hadoop项目,虽然我们只关心上面提到的两个子项目,但是为了防止后续出现依赖问题,在构建时请在项目根目录下执行命令:cd ~/hadoop-devmvn install -DskipTestsmvn eclipse:eclipse -DdownloadSources=true -DdownloadJavadocs=true
在执行mvn(即maven)命令时,请保证网络连接正常,因为mvn可能会下载一些Jar包来解决依赖问题。这可能需要花一段时间,完成上面的命令后,导入eclipse的准备工作已经做好了。在导入之前,我们还有一个工作,就是安装eclipse的maven插件。安装的方法这里不做介绍。接下来的工作是导入Eclipse中进行编译,打开eclipse,步骤如下:
[*]菜单File->Import...
[*]选择"Existing Projects into workspace"
[*]选择hadoop-dev目录下的 hadoop-common-project 目录作为根目录
[*]选择hadoop-annotations, hadoop-auth, hadoop-auth-examples, hadoop-nfs 和 hadoop-common projects
[*]单击 "Finish"
[*]菜单File->Import...
[*]选择"Existing Projects into workspace"
[*]选择hadoop-dev目录下的hadoop-assemblies目录作为根目录
[*]选择hadoop-assemblies project
[*]单击"Finish"
[*]菜单File->Import...
[*]选择"Existing Projects into workspace"
[*]选择hadoop-dev目录下的hadoop-hdfs-project目录作为根目录
[*]选择hadoop-hdfs project
[*]单击"Finish"
由于我的项目只要用到hadoop的这几个模块,因此只导入了hadoop的部分模块,如果你们想导入其他的模块进行二次开发,可按上面相同的方式导入相应的子项目。接下来就是利用eclipse编译hadoop,单击Run->Run Configuration...,会打开运行配置对话框,我们可以看到左侧有个Maven Build,双击Maven Build会新建一个配置页,按照下图的方式填写注意,Base directory 填写的是hadoop项目的根目录,即 ~/hadoop-dev。单击Run,hadoop项目就开始编译了,这需要花一些时间,注意在这期间请保持网络连接正常。原因同上。其实上面的过程也可以由命令行来完成,eclipse插件那一步都可以省了,命令行编译方法如下:cd ~/hadoop-devmvn package -Pdist -DskipTests -Dtar
回到eclipse,编译成功后,eclipse的console窗口会输出BUILD SUCESS信息,这表示hadoop项目已经编译成功。为了调试hadoop, 接下来的工作就是利用上面编译成功的hadoop构建hadoop环境。前面编译的结果都保存在各个项目的target目录下,以hadoop-common为例,编译的结果在 ~/hadoop-dev/hadoop-common-project/hadoop-common/target/hadoop-common-3.0.0-SNAPSHOT/ 下。这个目录下面的结构如下图:其他的比如hadoop-hdfs、hadoop-mapreduce等也在对应的target目录下,路径与上面的类似,里面的目录结构和上图是一样的。我们首先在用户目录下建立一个hadoop目录(mkdir ~/hadoop),把上图的所在目录下的所有项拷贝到这个新建的目录下,由于我只用common和hdfs,因此我的拷贝过程只针对这两个子项目。(目前我们有找到很好的方法编译,只能编译好后再从各个子项目中去拷贝,有解决方案的童鞋请一定留言~)由于上面的过程比较繁琐,我写成了一个脚本,稍后会发布到github上(附上github上脚本的地址:https://github.com/meibenjin/hadoop2.0-configuration),如果你等不及了,就先将就着拷贝一下吧。完成上面的操作以后,~/hadoop下的目录结构和上图一样。现在,我简单介绍一下新版的hadoop的目录结构, 看着很像linux的目录结构吧。 bin和sbin目录下是一些hadoop命令,ect目录下就是配置文件了。share目录下是hadoop需要用的一些jar包。hadoop的配置我就不在这里写了(如有必要,我另写一篇博客),具体的配置可上hadoop网站查看官方文档。也可以看这个博客:http://www.cnblogs.com/scotoma/archive/2012/09/18/2689902.html 其中提到的slaves和yarn-site.xml文件在hadoop-yarn-project下。 为了调试hadoop方便,请配置成伪分布模式。配置成功以后,启动hadoop相关的进程,命令如下:hadoop namenode -formatstart-dfs.sh
查看进程是否启动成功,输入命令,jps得到下图输出:这表示,hadoop相关的进程已经成功启动。 很好,学习一下。 mark,学习
howtodown 发表于 2014-1-16 17:35
在eclipse下远程调试hadoop2.0
Hadoop是一个分布式系统基础架构,由apache基金会维护并更新。官网地址: ht ...
你好,
在ubantu64位环境下,编译hadoop源码时,可以仅仅通过Ant吗
页:
[1]