一直认为Hadoop本身自带的HDFS和JobTracker监控页面是最好用的监控页面,简单明了。但是现在想要自己开发一套监控系统,那该怎样去获取Hadoop集群的当前状况呢?

  1. 网页抓取
    首先,想到的办法是抓取网页,通过抓取50030和50070页面获得监控的数据。不得不说,这个办法实在是太土了,不到万不得已真的不好意思用。
  2. Hadoop JMX 接口
    经过各种查阅,看到了一位大神写的文档(链接:http://slaytanic.blog.51cto.com/2057708/1179108),再次再膜拜一下这位大神吧。将http://namenode:50070/dfshealth.jsp 替换为 http://namenode:50070/jmx 就可以看到Hadoop自带的JMX接口所返回的JSON格式的数据,信息非常全面。同时,可以在链接的后面,添加参数来获取指定名称的监控信息,例如访问 http://namenode:50070/jmx?qry=Hadoop:service=NameNode,name=NameNodeInfo 就可以只获取NameNodeInfo的信息,通过更改qry=后面的参数,可以指定想要获取的内容,qry参数的值即为json信息中name所对应的内容。
    通过同样的方法,可以获得:
    JobTracker的信息:http://namenode:50030/jmxDataNode的信息:http://datanode:50075/jmxTaskTracker信息:http://datanode:50060/jmx上面这些链接基本上可以提供所有想要监控的信息了,但是,找了一圈儿也没找到我想要的Job列表,包括正在运行的作业、成功的作业以及失败的作业信息。
  3. Hadoop API 
    这时想到了早期版本的Hadoop API提交作业的时候都会用的JobClient这个类,抱着试试看的态度,去Hadoop API里面翻了半天,还真有收获。
    直接上干货了:


    [java]view plaincopy
  1. Configuration conf = new Configuration();  
  2. InetSocketAddress inetSocket = new InetSocketAddress(MonitorUtil.getHostnameOfNamenode(), 9001);  
  3. JobClient jobClient = new JobClient(inetSocket, conf);  
  4. JobStatus[] jobsStatus = jobClient.getAllJobs();  
  5. //这样就得到了一个JobStatus数组,随便取出一个元素取名叫jobStatus  
  6. jobStatus = jobsStatus[0];  
  7. JobID jobID = jobStatus.getJobID(); //通过JobStatus获取JobID  
  8. RunningJob runningJob = jobClient.getJob(jobID);  //通过JobID得到RunningJob对象  
  9. runningJob.getJobState();//可以获取作业状态,状态有五种,为JobStatus.Failed 、JobStatus.KILLED、JobStatus.PREP、JobStatus.RUNNING、JobStatus.SUCCEEDED  
  10. jobStatus.getUsername();//可以获取运行作业的用户名。  
  11. runningJob.getJobName();//可以获取作业名。  
  12. jobStatus.getStartTime();//可以获取作业的开始时间,为UTC毫秒数。  
  13. runningJob.mapProgress();//可以获取Map阶段完成的比例,0~1,  
  14. runningJob.reduceProgress();//可以获取Reduce阶段完成的比例。  
  15. runningJob.getFailureInfo();//可以获取失败信息。  
  16. runningJob.getCounters();//可以获取作业相关的计数器,计数器的内容和作业监控页面上看到的计数器的值一样。  
  17. 计数器这块稍微有点儿麻烦,举个例子吧。想要获得HDFS_BYTES_READ的值,方法为:

[java]  view plain  copy

  1. runningJob.getCounters().getGroup("FileSystemCounters").getCounter("HDFS_BYTES_READ");  
  2. 这里的FileSystemCounters为Group的名称,以该名称作为getGrout的参数可以取得相应的Group。Group的名称和50030页面上看到的组的名称并不相同,对应关系为:

org.apache.hadoop.mapred.JobInProgress$Counter

Job Counters

org.apache.hadoop.mapreduce.lib.output.FileOutputFormat$Counter

File Output Format Counters

FileSystemCounters

FileSystemCounters

org.apache.hadoop.mapreduce.lib.input.FileInputFormat$Counter

File Input Format Counters

org.apache.hadoop.mapred.Task$Counter

Map-Reduce Framework

左边为getGroup函数参数名,后面为想要获取的组名称。

得到Group之后就可以通过计数器的名称来得到相应计数器的值了。