hadoop1.0.4;
昨天写了一篇blog,是关于获取hadoop集群任务运行信息的例子,仿照50030界面实现。但是昨天遇到一个问题,就是当集群是第一次启动的时候,获得不了JobID,然后就拼凑不了JobID了,这样对后面的程序会有影响,所以想获得集群的第一个JobID,看到这个JobID是由“job_”+JobTracker启动时间+“_0001”得到的,所以获得JobTracker的启动时间就是最终的任务了,昨天找了好久,但是还是没有找到。
今天忽然想到了一种思路:既然hadoop提交任务会获得JobID,那么我去看hadoop任务提交的源码不就可以了。
最后追到JobTracker的代码里面就有获得启动时间的代码,那么就获得JobTracker吧,new JobTracker(jobConf),额,但是JobTracker构造方法是受保护的,获取不到,好吧。然后我就在那个包下面写了一个类来继承这个JobTracker,提升为public,如下:
package org.apache.hadoop.mapred;
import java.io.IOException;
/**
* get the jobtracker identifier
* @author fansy
*
*/
public class JobTrackerChild extends JobTracker {
/**
* set the configuration
* get the jobtracker start time
* @param conf
* @throws IOException
* @throws InterruptedException
*/
public JobTrackerChild(JobConf conf) throws IOException, InterruptedException {
super(conf);
// TODO Auto-generated constructor stub
}
public String getTheTrackerIdentifier(){
return getTrackerIdentifier();
}
}
然后,测试代码:
package hadoop;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.JobTrackerChild;
public class GetJobId {
/**
* @param args
* @throws IOException
* @throws InterruptedException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Configuration conf=new Configuration();
conf.set("mapred.job.tracker", "ubuntu:9001");
JobConf jobConf=new JobConf(conf);
String identifier=new JobTrackerChild(jobConf).getTheTrackerIdentifier();
System.out.println(identifier);
}
}
额,结果报了这样一个错误:
13/12/19 21:30:47 INFO delegation.AbstractDelegationTokenSecretManager: Updating the current master key for generating delegation tokens
13/12/19 21:30:47 INFO delegation.AbstractDelegationTokenSecretManager: Starting expired delegation token remover thread, tokenRemoverScanInterval=60 min(s)
13/12/19 21:30:47 INFO delegation.AbstractDelegationTokenSecretManager: Updating the current master key for generating delegation tokens
13/12/19 21:30:47 INFO mapred.JobTracker: Scheduler configured with (memSizeForMapSlotOnJT, memSizeForReduceSlotOnJT, limitMaxMemForMapTasks, limitMaxMemForReduceTasks) (-1, -1, -1, -1)
13/12/19 21:30:47 INFO util.HostsFileReader: Refreshing hosts (include/exclude) list
13/12/19 21:30:47 INFO mapred.JobTracker: Starting jobtracker with owner as Administrator
Exception in thread "main" java.net.BindException: Problem binding to ubuntu/192.168.128.130:9001 : Cannot assign requested address: bind
at org.apache.hadoop.ipc.Server.bind(Server.java:227)
at org.apache.hadoop.ipc.Server$Listener.(Server.java:301)
at org.apache.hadoop.ipc.Server.(Server.java:1483)
at org.apache.hadoop.ipc.RPC$Server.(RPC.java:546)
at org.apache.hadoop.ipc.RPC.getServer(RPC.java:506)
at org.apache.hadoop.mapred.JobTracker.(JobTracker.java:2307)
at org.apache.hadoop.mapred.JobTracker.(JobTracker.java:2192)
at org.apache.hadoop.mapred.JobTracker.(JobTracker.java:2186)
at org.apache.hadoop.mapred.JobTracker.(JobTracker.java:2167)
at org.apache.hadoop.mapred.JobTrackerChild.(JobTrackerChild.java:20)
at hadoop.GetJobId.main(GetJobId.java:22)
Caused by: java.net.BindException: Cannot assign requested address: bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:444)
at sun.nio.ch.Net.bind(Net.java:436)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:214)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at org.apache.hadoop.ipc.Server.bind(Server.java:225)
... 10 more
感觉是这个地址已经被另外一个用户(ubuntu上面的集群我是使用mahout用户启动的)启动了,所以我在myeclipse里面使用Administrator用户再新建一个JobTracker就会报错了(默认myeclipse发送的都是以Administrator用户来的或者说是win7登录用户)。
额,其实等它报错后,我才发现我想错了,不应该新建JobTracker的,(新建JobTrackerChild的时候就会新建一个JobTracker的),而是应该直接获取当前JobTracker的identifier属性的才对。
晕,居然想错了。然后网上又找,找到了一篇11年的文章:http://richardj.iteye.com/blog/1098244,这里说可以试试JobInProgress。
不过我没有试JobInProgress,因为打开JobInProgress看了下,然后又稍微试了下,感觉不行,然后就没继续试了。然而,我在那篇文章还是得到了一点启发:修改源码。其实我刚开始新建了一个JobTrackerChild也算是修改了源码吧,但是没有修改的那么明显。
怎么修改呢?看JobTracker的2485行,原来是这样的:
private static String generateNewIdentifier() {
return getDateFormat().format(new Date());
}
我改为了这样:
private static String generateNewIdentifier(JobConf conf) {
String startTime=getDateFormat().format(new Date());
writeString(startTime,conf);
return startTime;
}
其中的writeString就是把startTime写入文件,方法如下:
/**
* write to local file the start time
* @param value
*/
private static void writeString(String value,JobConf conf) {
LOG.info("***********************************prepare to wirte to file with value:"+value);
Path path=new Path("/private/jobtracker/starttime");
FileSystem fs;
FSDataOutputStream out=null;
try {
fs = FileSystem.get(path.toUri(),conf);
out = fs.create(path);
out.writeUTF(value);
} catch(Exception e){
LOG.info("********************************:"+e.getMessage());
}finally {
Closeables.closeQuietly(out);
}
}
针对上面的改法做如下的说明:
1. 传入了JobConf对象,因为JobTracker中的conf(其实就是JobConf对象)是非static的,但是generateNewIdentifier方法是static的,所以一定要new一个实例,但是new一个JobTracker实例违反获取当前JobTracker的初衷,所以采用传入JobConf对象。这里需要注意把调用generateNewIdentifier的方法全部都加上JobConf参数;包括293、2484、2165~2179之间的代码部分;
2. 为什么要传入一个JobConf对象呢?因为在writeString中需要使用JobConf对象获得FileSystem对象,然后写入数据。
编译后,替换hadoop-core-1.0.4.jar包,替换的文件如下:
重新启动hadoop集群,在hdfs文件系统上面查看/private/jobtracker/starttime文件,发现没有这个文件;那就说明没有进行文件信息写入。(那个文件目录是固定在代码中写死的)
然后我就开始怀疑有没有改到源码了,或者源码启动JobTracker是从这个入口进入的么?没办法,看有没有log信息吧,发现可以直接使用LOG.info()打印信息,好吧,用这个来看有没有改动吧。(修改的源码最后的样子就是上面的代码)
编译、替换、重启,好吧还没有那个文件,额,死心吧(其实,刚开始看到11年的那个文章,上面也说写入文件什么的都没有用,我就想小样儿,应该是写入hdfs文件吧,你应该是写入本地了吧,肯定不行的啦,结果自己试了试,居然还真写不了hdfs,哎。。。)
直接查看log信息吧,如下:
结果你都看到了,额,的确是写入错误,因为是safemode,所以这里会有问题,哎。
那就想要不要在safemode关闭后再写入呢?等等。。。
其实,这里已经很明显了,可以在log中记录这个信息,然后去搜索log,找到JobTracker启动的参数(话说回来,其实log里面已经包括JobTracker启动参数了),最简单的做法,如果你不想使用log本来的信息,比如希望像上面图片那样直接一个匹配就可以找到值(上面图片匹配的字符串可以认为是”***********************************prepare to wirte to file with value:“)。这样就不用解析log了,直接匹配自己固定写的字符串即可(其实也算是简单的解析了)。
额,好吧,又是一整晚。哎,又是连着盯着屏幕几个钟头,要近视的节奏。。。
如果您觉得lz的blog或者资源还ok的话,可以选择给lz投一票,多谢。(投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/fansy1990 )
分享,成长,快乐
转载请注明blog地址:http://blog.csdn.net/fansy1990