接触Hadoop已经一年半了,期间积累了一些Hadoop运维经验,一直想自己开发一套Hadoop监控系统,正好最近实验室有个相关的项目,就借机研究了一下,在这里总结一下Hadoop监控办法。
一直认为Hadoop本身自带的HDFS和JobTracker监控页面是最好用的监控页面,简单明了。但是现在想要自己开发一套监控系统,那该怎样去获取Hadoop集群的当前状况呢?
- 网页抓取
首先,想到的办法是抓取网页,通过抓取50030和50070页面获得监控的数据。不得不说,这个办法实在是太土了,不到万不得已真的不好意思用。
- 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/jmx
DataNode的信息:http://datanode:50075/jmx
TaskTracker信息:http://datanode:50060/jmx
上面这些链接基本上可以提供所有想要监控的信息了,但是,找了一圈儿也没找到我想要的Job列表,包括正在运行的作业、成功的作业以及失败的作业信息。
- Hadoop API
这时想到了早期版本的Hadoop API提交作业的时候都会用的JobClient这个类,抱着试试看的态度,去Hadoop API里面翻了半天,还真有收获。
直接上干货了:Configuration conf = new Configuration();
计数器这块稍微有点儿麻烦,举个例子吧。想要获得HDFS_BYTES_READ的值,方法为:
InetSocketAddress inetSocket = new InetSocketAddress(MonitorUtil.getHostnameOfNamenode(), 9001);
JobClient jobClient = new JobClient(inetSocket, conf);
JobStatus[] jobsStatus = jobClient.getAllJobs();
//这样就得到了一个JobStatus数组,随便取出一个元素取名叫jobStatus
jobStatus = jobsStatus[0];
JobID jobID = jobStatus.getJobID(); //通过JobStatus获取JobID
RunningJob runningJob = jobClient.getJob(jobID); //通过JobID得到RunningJob对象
runningJob.getJobState();//可以获取作业状态,状态有五种,为JobStatus.Failed 、JobStatus.KILLED、JobStatus.PREP、JobStatus.RUNNING、JobStatus.SUCCEEDED
jobStatus.getUsername();//可以获取运行作业的用户名。
runningJob.getJobName();//可以获取作业名。
jobStatus.getStartTime();//可以获取作业的开始时间,为UTC毫秒数。
runningJob.mapProgress();//可以获取Map阶段完成的比例,0~1,
runningJob.reduceProgress();//可以获取Reduce阶段完成的比例。
runningJob.getFailureInfo();//可以获取失败信息。
runningJob.getCounters();//可以获取作业相关的计数器,计数器的内容和作业监控页面上看到的计数器的值一样。runningJob.getCounters().getGroup("FileSystemCounters").getCounter("HDFS_BYTES_READ");
这里的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之后就可以通过计数器的名称来得到相应计数器的值了。
这里可以提供的信息已经很全面了,不过缺少了一个作业运行时间,或者作业的结束时间。对于正在运行的作业倒是可以通过当前时间减去开始时间来获得运行时间,但是结束时间目前还没找到解决办法。如果有知道的朋友,可以告诉我,感激不尽。
网上看到一篇博客(http://blog.sina.com.cn/s/blog_4a1f59bf0100nv03.html),提到Cluster类提供了更丰富的API接口,这个应该是要求Hadoop2.0以上的版本,由于不能升级实验室的Hadoop所以就没有测试。