Winse Blog

走走停停都是风景, 熙熙攘攘都向最好, 忙忙碌碌都为明朝, 何畏之.

Ant实现hadoop插件Run-on-Hadoop

撇开eclipse的插件不说,如果直接在eclipse运行main方法,运行的时刻会提示map,reduce找不到的错误。其实就是没有把需要类的包提供给集群环境。

看过使用hadoop-eclipse-plugin插件(http://winseclone.iteye.com/blog/1837035)最后解析的Run-on-Hadoop的实现,不难得出下面的方法步骤:

  • 首先打包jar,
  • 然后把jar的路径给Main的-Dmapred.jar参数。

这样,就可以把环境需要的class上传到hadoop了。

主要的ant代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<property name="exported.jar" value="${build.dir}/tmp-runonhadoop-${now}.jar"></property>

<target name="jar" depends="build" description="Make tmp-run.jar">
  <jar jarfile="${exported.jar}" basedir="${build.classes}">
      <fileset dir="${build.classes}" includes="**/example/*" />
      <exclude name="**/core-site.xml"/>
  </jar>
</target>

<target name="WordCount" depends="build, jar" >
  <java classname="com.winse.hadoop.examples.WordCount" failonerror="true" fork="yes">
      <arg line="-fs=${fs.default.name} -jt=${mapred.job.tracker} -Dmapred.jar=${exported.jar} /test/input /test/output"/>

      <classpath refid="runon.classpath"/>
  </java>
</target>

源码

其实就build.xml重要,其他就是exmaples里面的wordcount的源码而已。 其实build.xml也不重要,重要的思路!思路清晰了做事情就八九不离十了!


【原文地址】

–END

使用hadoop-eclipse-plugin插件

一直使用hadoop但都没有用过hadoop-plugins插件,倒不是看不上这个插件的意思。只是个人感觉使用SecureCRT太好用了。上传一个jar直接一拉进去使用lrzsz(z-moden)就直接搞定了。

但,身边搞hadoop的大部分都使用,今天略有兴致的弄了一弄,把环境hadoop-eclipse-plugins整起来了。在公司本来就使用插件来开发的,同时也看看Run-on-Hadoop的大致的实现。

环境准备:

  • eclipse-jee-3.7
  • jdk7
  • hadoop-1.0.0

插件编译-导出-安装

打开eclipse,把hadoop-1.0.0\src\contrib\eclipse-plugin整个工程导入(本来就是一个eclipse的project)。工程的lib目录下面已经包括了hadoop-core-1.0.0.jar包,但是hadoop-core-1.0.0.jar需要其他的依赖的jar包。我把这些依赖的jar从hadoop-1.0.0\lib下面复制到eclipse的/MapReduceTools/lib目录下。

然后,打开eclipse的/MapReduceTools/META-INF/MANIFEST.MF文件,切换到Runtime标签页,在classpath区域点击“Add…”添加lib下面的所有jar。

然后,再切换到Overview标签页,导出插件。

导出以后,把导出的插件拷贝都eclipse/dropins目录下。

然后重启。

配置环境:

  1. 设置HADOOP_HOME的位置。

    设置Preferences中的Hadoop Map/Reduce的Hadoop installation directory为你hadoop的主目录。我这里是C:\cygwin\home\Winseliu\hadoop-1.0.0(主要是用来把hadoop/lib下的包加入到MapRed Project的classpath)。

  2. 切换到Mapreduce透视图(Window | Open Perspective | other | Map/Reduce),然后新建一个Hadoop Location。操作如图:

  3. 然后,如果集群启动了,就可以看到下图的效果了。

    mapred插件提供的MapReduce Driver类还是不错的,把从写JobMain繁琐的工作中稍稍解放了一点。

Run-on-Hadoop的实现

一般我们在设置Job(JobConf).setJarByClass(WordCount.class)都是设置Main对应的主类。

查看源码,就可以得知。其实最终,设置了conf的mapred.jar属性!在提交的job时刻,会把该属性对应的jar拷贝到HDFS,最后发布到每台运行的机器上。

所以,也就是说,只要把需要的class导出为jar,然后把该jar对应的路径给mapred.jar的属性即可。

理着这思路,在源码中有org.apache.hadoop.eclipse.server.JarModule类调用JDT的JarPackageData来处理jar的导出工作。

JarModule类在org.apache.hadoop.eclipse.servers.RunOnHadoopWizard.performFinish()方法中被调用。也就是点击Run-on-Hadoop菜单后弹出的对话框的Finish按钮被点击时。

然后,会把该jar的路径写入到core-site.xml的配置文件中。该core-site.xml文件的路径会被加入到classpath,也就说Main方法的Configuration会加载这个配置文件!把conf的目录加入到classpath:

1
2
3
4
5
6
7
8
  classPath =
          iConf.getAttribute(
              IJavaLaunchConfigurationConstants.ATTR_CLASSPATH,
              new ArrayList());
  IPath confIPath = new Path(confDir.getAbsolutePath());
      IRuntimeClasspathEntry cpEntry =
          JavaRuntime.newArchiveRuntimeClasspathEntry(confIPath);
      classPath.add(0, cpEntry.getMemento());

后面的步骤就和一个普通的java类被调用一样的效果咯!

发布到集群运行的包涉及影响的文件:

参考资源:


【原文地址】

–END

Windows配置hadoop伪分布式环境(续)

在前一篇文章中,介绍了一写常见问题的解决方法。

但是,当我重装系统,再次按照前面一篇文章 安装cygwin和hadoop-1时,发现伪分布式环境使用mapred时,总是报错。(忘了,但是好像当时没有遇到过这种情况。就当是安装win8送给自己的礼物吧!)。

怀疑了很多东西,配置有问题,重新自定hadoop.tmp.dir,把hadoop-1.1.0换成hadoop-1.0.0等等。

错误日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ hhadoop fs -rmr /test/output ; hhadoop jar hadoop-examples-1.0.0.jar wordcount /test/input /test/output
Deleted hdfs://WINSE:9000/test/output
13/03/23 22:46:07 INFO input.FileInputFormat: Total input paths to process : 1
13/03/23 22:46:08 INFO mapred.JobClient: Running job: job_201303232144_0002
13/03/23 22:46:09 INFO mapred.JobClient:  map 0% reduce 0%
13/03/23 22:46:16 INFO mapred.JobClient: Task Id : attempt_201303232144_0002_m_000002_0, Status : FAILED
java.lang.Throwable: Child Error
        at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:272)
Caused by: java.io.IOException: Task process exit with nonzero status of -1.
        at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:259)

13/03/23 22:46:16 WARN mapred.JobClient: Error reading task outputhttp://WINSE:50060/tasklog?plaintext=true&attemptid=attempt_201303232144_0002_m_000002_0&filter=stdout
13/03/23 22:46:16 WARN mapred.JobClient: Error reading task outputhttp://WINSE:50060/tasklog?plaintext=true&attemptid=attempt_201303232144_0002_m_000002_0&filter=stderr
13/03/23 22:46:22 INFO mapred.JobClient: Task Id : attempt_201303232144_0002_m_000002_1, Status : FAILED

经过不断的修改源码,加入sysout打印,算是最终找出程序出现错误的地方!

org.apache.hadoop.mapred.DefaultTaskController.java #launchTask org.apache.hadoop.mapred.JvmManager.java #runChild org.apache.hadoop.mapred.TaskRunner.java #launchJvmAndWait

org.apache.hadoop.fs.FileUtil.java #checkReturnValue org.apache.hadoop.fs.RawLocalFileSystem.java  #setPermission  #mkdirs

发现在org.apache.hadoop.fs.RawLocalFileSystem.mkdirs(Path)方法中,建立文件的路径方法检查attempt_201303232144_0002_m_000001_0是否为文件夹时会失败!

而在cygwin中查看文件属性:

1
2
3
4
5
6
7
8
9
10
11
12
Winseliu@WINSE ~/hadoop/logs/userlogs/job_201303232144_0002
$ ll
总用量 9
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000001_0 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000001_0
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000001_1 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000001_1
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000001_2 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000001_2
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000001_3 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000001_3
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000002_0 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000002_0
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000002_1 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000002_1
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000002_2 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000002_2
lrwxrwxrwx 1 Winseliu None  89 3月  23 22:46 attempt_201303232144_0002_m_000002_3 -> /cluster/mapred/local/userlogs/job_201303232144_0002/attempt_201303232144_0002_m_000002_3
-rwxr-xr-x 1 Winseliu None 404 3月  23 22:46 job-acls.xml

对于linux来说,这些就是引用到另一个文件夹,它本身应该也是文件夹!但是window的jdk不认识这些东西!

1
2
3
4
5
6
  public boolean mkdirs(Path f) throws IOException {
    Path parent = f.getParent();
    File p2f = pathToFile(f);
    return (parent == null || mkdirs(parent)) &&
      (p2f.mkdir() || p2f.isDirectory());
  }

所以在判断p2f.isDirectory()返回false,然后会抛出IOException,最终以-1的状态退出Map Child的程序!

其使用org.apache.hadoop.mapred.TaskRunner.prepareLogFiles(TaskAttemptID, boolean)方法来指定输出日志的位置。在最终执行的会在shell命令中把sysout和syserr输出到日志文件中( $COMMAND  1>>$stdout  2>>$stderr ,本文最后有贴运行时的cmd)。

而userlogs的父目录是使用hadoop.log.dir系统属性来进行配置的!

mapred.DefaultTaskController.launchTask()

|–mapred.TaskLog.buildCommandLine()

临时解决方法:

把hadoop.log.dir定位到真正mapred日志的目录( mapred.local.dir : ${hadoop.tmp.dir}/mapred/local )!

1
export HADOOP_LOG_DIR=/cluster/mapred/local

最终的效果,运行的程序会把日志输出到attempt目录下的stdout,stderr文件中。

1
2
3
4
5
6
7
8
Winseliu@WINSE /cluster/mapred/local/userlogs/job_201303240035_0001/attempt_201303240035_0001_m_000000_0
$ ll
总用量 6
lrwxrwxrwx  1 Winseliu None   89 3月  24 00:36 attempt_201303240035_0001_m_000000_0 -> /cluster/mapred/local/userlogs/job_201303240035_0001/attempt_201303240035_0001_m_000000_0
----------+ 1 Winseliu None  136 3月  24 00:36 log.index
-rw-r--r--+ 1 Winseliu None    0 3月  24 00:36 stderr
-rw-r--r--+ 1 Winseliu None    0 3月  24 00:36 stdout
----------+ 1 Winseliu None 1238 3月  24 00:36 syslog

上面的软链接是调用org.apache.hadoop.mapred.TaskLog.createTaskAttemptLogDir()生成的,本文最后有贴运行时ln命令及参数。

ln当linkname是一个已经存在文件夹时,会在linkname的文件夹下建立一个以targetname作为名称的链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Winseliu@WINSE ~/tt
$ mkdir f1

Winseliu@WINSE ~/tt
$ ln -s f1 f1

Winseliu@WINSE ~/tt
$ ls -Rl
.:
总用量 0
drwxr-xr-x+ 1 Winseliu None 0 3月  24 13:56 f1

./f1:
总用量 1
lrwxrwxrwx 1 Winseliu None 2 3月  24 13:56 f1 -> f1

把windows的/cluster映射到cygwin(linux)的/cluster:

1
2
3
4
5
6
7
Winseliu@WINSE ~/hadoop
$ ll /cygdrive/c | grep cluster
drwxr-xr-x+ 1 Winseliu         None                      0 3月  24 00:08 cluster

Winseliu@WINSE ~/hadoop
$ ll / | grep cluster
lrwxrwxrwx   1 Winseliu None     19 3月  23 09:39 cluster -> /cygdrive/c/cluster

但是,运行wordcount的例子时,还是不正常!查看tasktracker的日志时,发现有String转成Integer的NumberFormatException异常!

修改org.apache.hadoop.mapred.JvmManager.JvmManagerForType.JvmRunner.kill()方法。添加pidStr为空字符串的检查!

1
2
String pidStr = jvmIdToPid.get(jvmId);
if (pidStr != null && !pidStr.isEmpty()) {

然后,终于看到Finish咯!在/test/output/part-r-00000中也看到了结果。

其他一些简化处理,即配置文件:

1
2
3
4
5
6
7
8
9
alias startCluster="~/hadoop/bin/start-all.sh"
alias stopCluster="~/hadoop/bin/stop-all.sh; ~/hadoop/bin/stop-all.sh"

alias hhadoop="~/hadoop/bin/hadoop"

Winseliu@WINSE ~
$ ll | grep hadoop
lrwxrwxrwx  1 Winseliu None    12 3月  23 10:44 hadoop -> hadoop-1.0.0
drwx------+ 1 Winseliu None     0 3月  24 00:06 hadoop-1.0.0

配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!-- core-site.xml -->

<configuration>

<property>
<name>fs.default.name</name>
<value>hdfs://WINSE:9000</value>
</property>

<property>
<name>hadoop.tmp.dir</name>
<value>/cluster</value>
</property>

</configuration>

<!-- hdfs-site.xml -->

<configuration>

<property>
<name>dfs.replication</name>
<value>1</value>
</property>

<property>
  <name>dfs.permissions</name>
  <value>false</value>
</property>

<property>
  <name>dfs.permissions.supergroup</name>
  <value>None</value>
</property>

<property>
<name>dfs.safemode.extension</name>
<value>1000</value>
</property>

</configuration>

<!-- mapred-site.xml -->

<configuration>

<property>
<name>mapred.job.tracker</name>
<value>WINSE:9001</value>
</property>

</configuration>

关于查看启动的进程,看可以通过任务管理器来查看:

还可以看看pid的修改时间,来确认服务的启动:

我是经常通过50070和50030来查看的~~ 看到50030的Nodes为1时,就说明集群启动正常了。

 执行时的日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
cmd : ln -s /cluster/mapred/local\userlogs\job_201303241340_0001\attempt_201303241340_0001_m_000000_0 C:\cluster\mapred\local\userlogs\job_201303241340_0001\attempt_201303241340_0001_m_000000_0

cmdLine : export HADOOP_CLIENT_OPTS="-Dhadoop.tasklog.taskid=attempt_201303241340_0001_m_000000_0 -Dhadoop.tasklog.iscleanup=false -Dhadoop.tasklog.totalLogFileSize=0"
export SHELL="/bin/bash"
export HADOOP_WORK_DIR="\cluster\mapred\local\taskTracker\Winseliu\jobcache\job_201303241340_0001\attempt_201303241340_0001_m_000000_0\work"
export HOME="/homes/"
export LOGNAME="Winseliu"
export HADOOP_TOKEN_FILE_LOCATION="/cluster/mapred/local/taskTracker/Winseliu/jobcache/job_201303241340_0001/jobToken"
export HADOOP_ROOT_LOGGER="INFO,TLA"
export LD_LIBRARY_PATH="\cluster\mapred\local\taskTracker\Winseliu\jobcache\job_201303241340_0001\attempt_201303241340_0001_m_000000_0\work"
export USER="Winseliu"

exec '/cygdrive/c/Java/jdk1.7.0_02/jre/bin/java' '-Djava.library.path=/home/Winseliu/hadoop-1.0.0/lib/native/Windows_NT_unknown-x86-32;\cluster\mapred\local\
taskTracker\Winseliu\jobcache\job_201303241340_0001\attempt_201303241340_0001_m_000000_0\work' '-Xmx200m' '-Djava.net.preferIPv4Stack=true' '-Dhadoop.metrics
.log.level=WARN' '-Djava.io.tmpdir=/cluster/mapred/local/taskTracker/Winseliu/jobcache/job_201303241340_0001/attempt_201303241340_0001_m_000000_0/work/tmp' '
-classpath' 'C:\cygwin\home\Winseliu\conf;C:\Java\jdk1.7.0_02\lib\tools.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\;C:\cygwin\home\Winseliu\hadoop-1.0.0\hadoop
-core-1.0.0.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\asm-3.2.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\aspectjrt-1.6.5.jar;C:\cygwin\home\Winseliu\had
oop-1.0.0\lib\aspectjtools-1.6.5.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-beanutils-1.7.0.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-be
anutils-core-1.8.0.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-cli-1.2.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-codec-1.4.jar;C:\cygwin\
home\Winseliu\hadoop-1.0.0\lib\commons-collections-3.2.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-configuration-1.6.jar;C:\cygwin\home\Winseliu\h
adoop-1.0.0\lib\commons-daemon-1.0.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-digester-1.8.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-e
l-1.0.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-httpclient-3.0.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-lang-2.4.jar;C:\cygwin\home\
Winseliu\hadoop-1.0.0\lib\commons-logging-1.1.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-logging-api-1.0.4.jar;C:\cygwin\home\Winseliu\hadoop-1.0
.0\lib\commons-math-2.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\commons-net-1.4.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\core-3.1.1.jar;C:\cygwin\
home\Winseliu\hadoop-1.0.0\lib\hadoop-capacity-scheduler-1.0.0.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\hadoop-fairscheduler-1.0.0.jar;C:\cygwin\home\Win
seliu\hadoop-1.0.0\lib\hadoop-thriftfs-1.0.0.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\hsqldb-1.8.0.10.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jackso
n-core-asl-1.0.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jackson-mapper-asl-1.0.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jasper-compiler-5.5.12.ja
r;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jasper-runtime-5.5.12.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jdeb-0.8.jar;C:\cygwin\home\Winseliu\hadoop-1.0
.0\lib\jersey-core-1.8.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jersey-json-1.8.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jersey-server-1.8.jar;C:\cyg
win\home\Winseliu\hadoop-1.0.0\lib\jets3t-0.6.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jetty-6.1.26.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jetty-
util-6.1.26.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jsch-0.1.42.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\junit-4.5.jar;C:\cygwin\home\Winseliu\hadoo
p-1.0.0\lib\kfs-0.2.2.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\log4j-1.2.15.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\mockito-all-1.8.5.jar;C:\cygwin\
home\Winseliu\hadoop-1.0.0\lib\mysql-connector-java-5.1.10-bin.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\ojdbc6.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\l
ib\oro-2.0.8.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\servlet-api-2.5-20081211.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\slf4j-api-1.4.3.jar;C:\cygwin
\home\Winseliu\hadoop-1.0.0\lib\slf4j-log4j12-1.4.3.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\sqoop-1.4.1-incubating.jar;C:\cygwin\home\Winseliu\hadoop-1.
0.0\lib\xmlenc-0.52.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jsp-2.1\jsp-2.1.jar;C:\cygwin\home\Winseliu\hadoop-1.0.0\lib\jsp-2.1\jsp-api-2.1.jar;\cluste
r\mapred\local\taskTracker\Winseliu\jobcache\job_201303241340_0001\jars\classes;\cluster\mapred\local\taskTracker\Winseliu\jobcache\job_201303241340_0001\jar
s;\cluster\mapred\local\taskTracker\Winseliu\jobcache\job_201303241340_0001\attempt_201303241340_0001_m_000000_0\work' '-Dhadoop.log.dir=C:\cluster\mapred\lo
cal' '-Dhadoop.root.logger=INFO,TLA' '-Dhadoop.tasklog.taskid=attempt_201303241340_0001_m_000000_0' '-Dhadoop.tasklog.iscleanup=false' '-Dhadoop.tasklog.tota
lLogFileSize=0' 'org.apache.hadoop.mapred.Child' '127.0.0.1' '49203' 'attempt_201303241340_0001_m_000000_0' 'C:\cluster\mapred\local\userlogs\job_20130324134
0_0001\attempt_201303241340_0001_m_000000_0' '-1682417583'  < /dev/null  1>> /cygdrive/c/cluster/mapred/local/userlogs/job_201303241340_0001/attempt_20130324
1340_0001_m_000000_0/stdout 2>> /cygdrive/c/cluster/mapred/local/userlogs/job_201303241340_0001/attempt_201303241340_0001_m_000000_0/stderr

linux的版本的日志目录结构:


【原文地址】

–END

编译hadoop的jsp源码

从apache下载的tar.gz的hadoop-1.1.0包中本来就包括了src的源码。可以方便我们查看源码调试。

题外话: 从github上下载了最新的hadoop-common的源码,发现hadoop-2.0已经是使用maven管理代码了。

在eclipse中新建java project,去掉Use Default location的复选框的勾,项目目录为hadoop-1.1.0程序所在的位置。然后点击finish即可。

完成后,项目下面的lib包,以及Source Folder源码包都已经正确的配置好了。如下图。

编译hadoop的源码,需要用到sed,sh的linux shell命令(根据网上的资料)。安装好了cygwin,把c:\cygwin\bin加入到PATH环境变量。然后直接使用eclipse ant(eclipse自带)编译。

1
2
3
4
5
Winseliu@WINSE ~
$ cygcheck -c cygwin
Cygwin Package Information
Package              Version        Status
cygwin               1.7.17-1       OK

由于linux和windows的换行符的不同(同事周帅哥在导数据也遇到这样的问题),直接编译会失败。

需要对src/saveVersion.sh的shell文件进行修改:

1
2
-  user=`whoami`
+  user=`whoami | tr -d '\r'` 

然后再编译一次就ok了!


经过上面步骤已经可以正确的编译hadoop-core的源码了。

在监控集群的时刻,我们一般都在自己常用的windows系统上面通过50030和50070来了解集群的情况。但是如果没有域名服务器,那,我们就不得不修改hosts文件。在出现访问失败的情况下,我们可以使用ip地址替换URL中对应的hostname来访问,但是比较麻烦。

如果在服务器响应请求的时刻,解析生成html的时刻就已经是ip地址那就最好不过了! 其实,直接看看jsp的源码,修改起来不算太难。把jsp里面的hostname转换为IP地址即可。

把上图的hostname通过InetAddress获取转换为IpAddress地址。

1
2
3
4
5
-    String namenodeHost = jspHelper.nameNodeAddr.getHostName();
+    String namenodeHost = jspHelper.nameNodeAddr.getAddress().getHostAddress();

-              InetAddress.getByName(namenodeHost).getCanonicalHostName() + ":" +
+              InetAddress.getByName(namenodeHost).getHostAddress() + ":" +

全部修改完成后,再次运行hadoop-1.1.0 build.xml的ant命令,会调用自定义的jsp-compile把jsp转换成java类保存到build/src目录下面。然后javac再编译build/src目录下的源码。

如果你只想编译这些jsp,把javac中的srcdir的目录只保留build.src应该就可以咯。

我是直接把build/src作为Source Folder,然后把这个Source Folder下的编译文件放置的特定的目录,然后覆盖原来jar里面的class即可!

参考:


【原文地址】

–END

快速搭建第二个hadoop分布式集群环境

万事开头难,第一次搭建集群环境确实是比较难,比较苦恼。但,也不是说第二次搭建集群环境就会容易。

一般,第一次操作我们都会在测试环境中进行,当我们要搭建正式的环境时,是否还要像第一次那样搭建环境呢? 这里提供一种稍稍便捷一点的配置方式来搭建集群,所有的操作都在namenode上面进行!

192.168.3.100 h100为测试环境的namenode。

将要搭建的环境包括3台机器,已经全部安装好redhat的操作系统:

1
2
3
192.168.80.81 h81 #namenode
192.168.80.82 h82 #datanode1
192.168.80.83 h83 #datanode2

使用SecureCRT工具,root用户登录到新环境namenode。步骤参考,有些步骤需要输入密码(可以通过expect来模拟),不能一次性全部执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
## 生成root用户的密钥对
ssh-keygen 

## 建立到100机器的无密钥登录
ssh-copy-id -i .ssh/id_rsa.pub hadoop@192.168.3.100

## 拷贝JDK,将加入hadoop用户的环境变量
mkdir -p /opt/java
scp -r hadoop@192.168.3.100:/opt/java/jdk1.6.0_29 /opt/java

## 把集群的IP和机器名对应加入hosts文件
vi /etc/hosts

# 192.168.80.81 h81
# 192.168.80.82 h82
# 192.168.80.83 h83

## 定义常量
namenode='h81'
hosts=`cat /etc/hosts | grep 192.168 | awk '{print $2}'`

## 修改时间,~~可以日期和时间一起修改的~~
DATE='2013-03-01'
TIME='10:30:00'

for host in $hosts
do
  ssh $host date -s $DATE
  ssh $host date -s $TIME
done

## 建立namenode到datanodes的无密钥访问,这里需要输入对应datanode的root用户的密码
for host in $hosts
do
  ssh-copy-id -i .ssh/id_rsa.pub $host
done

#### 
for host in $hosts
do
  ## 在集群所有节点上创建hadoop用户,会提示很多次输入密码。可以通过修改/etc/shadow替换密码输入的步骤
  ssh $host useradd hadoop
  ssh $host passwd hadoop

  ## 拷贝jdk到datanodes
  if [ $host != $namenode ]
  then
      scp /etc/hosts $host:/etc/hosts
      ssh $host mkdir -p /opt/java
      scp -r /opt/java/jdk1.6.0_29 $host:/opt/java 2>&1 > jdk.scp.$host.log & 
  fi

  ## 修改集群的hostname主机名称
  ssh $host hostname $host
  ssh $host cat /etc/sysconfig/network | sed s/localhost.localdomain/$host/g > /tmp/network && cat /tmp/network > /etc/sysconfig/network

  ## 创建数据目录,并把权限分配给hadoop
  ssh $host mkdir /opt/cloud
  ssh $host chown hadoop /opt/cloud

done

## !切换到hadoop用户
su - hadoop

## 生成hadoop用户的密钥对
ssh-keygen

## 在hadoop用户的终端定义变量(root的终端变量获取不到的)
namenode='h81'
hosts=`cat /etc/hosts | grep 192.168 | awk '{print $2}'`

## 使namenode的hadoop用户无密钥登录到集群各个机器
for host in $hosts
do
  ssh-copy-id -i .ssh/id_rsa.pub $host
done

## 更新hadoop用户的环境变量,
vi .bashrc

# export JAVA_HOME=/opt/java/jdk1.6.0_29
# PATH=$JAVA_HOME/bin:/usr/sbin:$PATH
# export PATH

## 修改datanodes的环境环境变量,同时为集群创建必要的目录
for host in $hosts
do
  if [ $host != $namenode ]
  then
      scp .bashrc $host:~/.bashrc
  fi

  ssh $host source .bashrc
  ssh $host mkdir -p /home/hadoop/cloud/zookeeper
  ssh $host mkdir -p /home/hadoop/pids/katta/pids
  ssh $host mkdir -p /home/hadoop/pids/hadoop/pids 

done

## 建立namenode下的hadoop用户到192.168.3.100的无密钥访问
ssh-copy-id -i .ssh/id_rsa.pub 192.168.3.100

## 从100上拷贝集群程序
rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/lucene ~/
rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/sqoop-1.4.1 ~/
rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/zookeeper-3.3.5 ~/

rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/hadoop-1.0.0 ~/
rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/hbase-0.92.1 ~/
rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/katta-core-0.6.4 ~/
rsync -vaz --delete  --exclude=logs --exclude=log  192.168.3.100:~/lucene-shared-lib ~/

## 查找配置文件中与测试环境有关的信息
[hadoop@h81 ~]$ find */conf | while read conf; do if grep -E 'h100|192.168.3.100' $conf > /dev/null; then echo $conf;fi;done
hadoop-1.0.0/conf/mapred-site.xml
hadoop-1.0.0/conf/core-site.xml
hadoop-1.0.0/conf/masters
hbase-0.92.1/conf/hbase-site.xml
katta-core-0.6.4/conf/katta.zk.properties
katta-core-0.6.4/conf/masters
lucene/conf/config-env.sh
[hadoop@h81 ~]$ 

## 替换为新的nameode的hostname
find */conf | while read conf; do if grep -E 'h100|192.168.3.100' $conf > /dev/null; then  cat $conf | sed s/h100/h81/g > /tmp/conf && cat /tmp/conf > $conf ;fi;done

## 修改其他配置
vi hadoop-1.0.0/conf/slaves
vi hbase-0.92.1/conf/regionservers
vi katta-core-0.6.4/conf/nodes

## 确认是否还有原有集群的余孽!
find */conf | while read conf; do if grep -E 'h10' $conf > /dev/null; then echo $conf;fi;done

## 拷贝集群程序到datanodes
for host in $hosts
do
  if [ $host != $namenode ]
  then
      rsync -vaz --delete  --exclude=logs --exclude=log  ~/hadoop-1.0.0 $host:~/ &
      rsync -vaz --delete  --exclude=logs --exclude=log  ~/hbase-0.92.1 $host:~/ &
      rsync -vaz --delete  --exclude=logs --exclude=log  ~/katta-core-0.6.4 $host:~/ &
      rsync -vaz --delete  --exclude=logs --exclude=log  ~/lucene-shared-lib $host:~/ &
  fi
done

如果你觉得sed修改麻烦,要备份,在写回!其实有sed -i(–in-place)参数提供了直接写入的功能。

在批处理文件内容替换时,使用到了临时文件,当然也可以先把文件备份后,再写入新文件中,如下面的方式。 但,先备份再写入新文件 有个缺陷就是原始文件的权限会丢失!

1
2
3
ssh $host \
mv /etc/sysconfig/network /etc/sysconfig/network.back && \ 
cat /etc/sysconfig/network.back | sed s/localhost.localdomain/$host/g > /etc/sysconfig/network

最后你懂的:

1
2
 hadoop-1.0.0/bin/hadoop namenode -format
 hadoop-1.0.0/bin/start-all.sh

通过for,scp, ssh, sed, awk,rsync,vi, find,ssh-copy-id, mkdir等命令仅在namenode上完成集群的部署工作。

仅新增节点,又不想修改namenode配置文件!可以用下面的方法启动新节点:

1
2
3
4
5
6
7
[hadoop@h101 ~]$ hadoop-1.0.0/bin/hadoop-daemon.sh start datanode

starting datanode, logging to /home/hadoop/hadoop-1.0.0/libexec/../logs/hadoop-hadoop-datanode-h101.out

[hadoop@h101 ~]$ hadoop-1.0.0/bin/hadoop-daemon.sh start tasktracker

starting tasktracker, logging to /home/hadoop/hadoop-1.0.0/libexec/../logs/hadoop-hadoop-tasktracker-h101.out

【原文地址】

–END