hadoop JobTracker获取启动时间

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 JobTracker获取启动时间_第1张图片

重新启动hadoop集群,在hdfs文件系统上面查看/private/jobtracker/starttime文件,发现没有这个文件;那就说明没有进行文件信息写入。(那个文件目录是固定在代码中写死的)

然后我就开始怀疑有没有改到源码了,或者源码启动JobTracker是从这个入口进入的么?没办法,看有没有log信息吧,发现可以直接使用LOG.info()打印信息,好吧,用这个来看有没有改动吧。(修改的源码最后的样子就是上面的代码)

编译、替换、重启,好吧还没有那个文件,额,死心吧(其实,刚开始看到11年的那个文章,上面也说写入文件什么的都没有用,我就想小样儿,应该是写入hdfs文件吧,你应该是写入本地了吧,肯定不行的啦,结果自己试了试,居然还真写不了hdfs,哎。。。)

直接查看log信息吧,如下:

hadoop JobTracker获取启动时间_第2张图片
结果。。。

结果你都看到了,额,的确是写入错误,因为是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





你可能感兴趣的:(JobTracker,hadoop,mapreduce)