监控Tomcat解决方案.docx
《监控Tomcat解决方案.docx》由会员分享,可在线阅读,更多相关《监控Tomcat解决方案.docx(14页珍藏版)》请在冰豆网上搜索。
监控Tomcat解决方案
监控Tomcat解决方案(监控应用服务器系列文章)
前言:
做了一个监控应用服务器的项目(支持Tocmat、WebSphere、WebLogic各版本),过程也算是磕磕绊绊,由于网上缺少相关资料,或者深陷于知识的海洋难以寻觅到有效的资料,因而走过不少弯路,遇过不少困难。
为了留下点印记,给后来人留下点经验之谈,助之少走弯路,故将这些经验整理出来,与大家分享。
水平有限,难免疏漏,还望指正。
如有疑问,欢迎留言,或者加入Q群参与讨论:
35526521。
对监控Tomcat的前期方案调研,共有两种方案,比较如下
使用Tomcat提供的manager应用进行数据采集
◆可以使用现有的成熟代码,减少工作量
◆支持各不同版本时无差别
◆可能存在特殊需求而manager不能满足的情况
◆最重要的一个优点是,配置比较简单
使用JMX接口开发监控程序
◆全部代码需要从零开始,代码量较大
◆支持各不同版本比较麻烦,每个版本可能有差异
◆可支配性强
◆最重要的一个缺点是,配置比较麻烦
方案一、使用Tomcat提供的manager应用进行数据采集
ManageEngineApplicationsManager(又称opManager)就是通过这种方式实现的。
使用这种方式,所监控Tomcat必须运行manager应用,缺省情况下,该应用总是运行在服务器中的。
增加manager角色用户
访问manager应用的用户的角色权限必须是manager.
修改/conf目录下的tomcat-users.xml文件,在节点下添加一个user节点,即可创建一个用户。
Tomcat版本不同配置也有差异,5.x和6.x创建的用户角色应为manager,7.x创建的用户角色为manager-jmx,举例如下:
1、在5.x和6.x中创建一个manager角色的用户,用户名为admin,密码为admin123:
2、在7.x中创建一个manager角色的用户,用户名为admin,密码为admin123:
修改配置后,需要重新启动Tomcat服务器。
连接manager时将用户名/密码指定为chenfeng/chenfeng
通过浏览器访问JMXProxyServlet
详见官方说明文档:
http:
//tomcat.apache.org/tomcat-6.0-doc/manager-howto.html#Using_the_JMX_Proxy_Servlet
WhatisJMXProxyServlet
TheJMXProxyServletisalightweightproxytogetandsetthetomcatinternals.(OranyclassthathasbeenexposedviaanMBean)ItsusageisnotveryuserfriendlybuttheUIisextremelyhelpforintegratingcommandlinescriptsformonitoringandchangingtheinternalsoftomcat.Youcandotwothingswiththeproxy:
getinformationandsetinformation.ForyoutoreallyunderstandtheJMXProxyServlet,youshouldhaveageneralunderstandingofJMX.Ifyoudon'tknowwhatJMXis,thenpreparetobeconfused.
JMXQuerycommand
Thistakestheform:
http:
//webserver/manager/jmxproxy/?
qry=STUFF
WhereSTUFFistheJMXqueryyouwishtoperform.Forexample,herearesomequeriesyoumightwishtorun:
◆qry=*%3Atype%3DRequestProcessor%2C*-->type=RequestProcessorwhichwilllocateallworkerswhichcanprocessrequestsandreporttheirstate.
◆qry=*%3Aj2eeType=Servlet%2c*-->j2eeType=Servletwhichreturnallloadedservlets.
◆qry=Catalina%3Atype%3DEnvironment%2Cresourcetype%3DGlobal%2Cname%3DsimpleValue-->Catalina:
type=Environment,resourcetype=Global,name=simpleValuewhichlookforaspecificMBeanbythegivenname.
You'llneedtoexperimentwiththistoreallyunderstanditscapabilites.Ifyouprovidenoqryparameter,thenalloftheMBeanswillbedisplayed.WereallyrecommendlookingatthetomcatsourcecodeandunderstandtheJMXspectogetabetterunderstandingofallthequeriesyoumayrun.
通过浏览器访问http:
//localhost:
8080/manager/jmxproxy,输入用户名密码,然后就可以看到返回了所有的监控信息
添加查询参数,返回特定的监控信息:
例如http:
//localhost:
8080/manager/jmxproxy?
qry=*%3Atype%3DRequestProcessor%2C*
其中*%3Atype%3DRequestProcessor%2C*其实就是*:
type=RequestProcessor,*
又如http:
//localhost:
8080/manager/jmxproxy?
qry=*%3Aj2eeType%3DWebModule%2Cname%3D//localhost/ajaxrpc%2C*
在代码中访问JMXProxyServlet
通过浏览器访问JMXProxyServlet需要输入用户名密码,所以通过Java访问JMXProxyServlet的URL也需要授权访问:
URLurl=newURL("http:
//localhost:
8080/manager/jmxproxy?
qry=*%3Atype%3DManager%2C*");
URLConnectionconn=(URLConnection)url.openConnection();
//URL授权访问--Begin
Stringpassword="admin:
chenfeng";//manager角色的用户
StringencodedPassword=newBASE64Encoder().encode(password.getBytes());
conn.setRequestProperty("Authorization","Basic"+encodedPassword);
//URL授权访问--End
InputStreamis=conn.getInputStream();
BufferedReaderbufreader=newBufferedReader(newInputStreamReader(is));
Stringline=null;
while((line=bufreader.readLine())!
=null){
System.out.println(line);
}
几个具体的例子
下面展示两个例子,一个是采集服务器基本信息,一个是采集Web应用列表信息,注意Tomcat7.x和Tomcat5.x、6.x之间存在很大的区别。
◆采集服务器基本信息
通过serverinfo命令查看服务器基本信息
http:
//localhost:
8080/manager/serverinfo
Tomcat7.x的查询URL有变化:
http:
//localhost:
8080/manager/text/serverinfo
返回信息:
OK-Serverinfo
TomcatVersion:
ApacheTomcat/7.0.11
OSName:
WindowsVista
OSVersion:
6.1
OSArchitecture:
x86
JVMVersion:
1.6.0_13-b03
JVMVendor:
SunMicrosystemsInc.
◆采集Web应用列表信息
通过list命令查看Web应用列表和会话数信息
http:
//localhost:
8080/manager/list
Tomcat7.x的查询URL有变化:
http:
//localhost:
8080/manager/text/list
返回信息:
OK-Listedapplicationsforvirtualhostlocalhost
/:
running:
0:
ROOT
/manager:
running:
1:
manager
/docs:
running:
0:
docs
/examples:
running:
0:
examples
/host-manager:
running:
0:
host-manager
方案二、使用JMX接口开发监控程序
Tomcat激活JMX远程配置
①■ 先修改Tomcat的启动脚本,window下tomcat的bin/catalina.bat(linux为catalina.sh),添加以下内容,8999是jmxremote使用的端口号,第二个false表示不需要鉴权:
setJMX_REMOTE_CONFIG=-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=8999-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=false
setCATALINA_OPTS=%CATALINA_OPTS%%JMX_REMOTE_CONFIG%
可以加在if"%OS%"=="Windows_NT"setlocal一句后的大段的注释后面。
参考官方说明:
http:
//tomcat.apache.org/tomcat-6.0-doc/monitoring.html#Enabling_JMX_Remote
②■ 上面的配置是不需要鉴权的,如果需要鉴权则添加的内容为:
setJMX_REMOTE_CONFIG=-Dcom.sun.management.jmxremote-Dcom.sun.management.jmxremote.port=8999-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=true-Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
setCATALINA_OPTS=%CATALINA_OPTS%%JMX_REMOTE_CONFIG%
然后复制并修改授权文件,$JAVA_HOME/jre/lib/management下有jmxremote.access和jmxremote.password的模板文件,将两个文件复制到$CATALINA_BASE/conf目录下
●修改$CATALINA_BASE/conf/jmxremote.access添加内容:
monitorRolereadonly
controlRolereadwrite
●修改$CATALINA_BASE/conf/jmxremote.password添加内容:
monitorRoletomcat
controlRoletomcat
注意:
如果只做第一步没有问题,进行了第二步Tomcat就启动不了,那么很可能是密码文件的权限问题
需要修改jmxremote.password文件的权限,只有运行Tomcat的用户有访问权限
Windows的NTFS文件系统下,选中文件,点右键-->“属性”-->“安全”-->点“高级”-->点“更改权限”-->去掉“从父项继承....”-->弹出窗口中选“删除”,这样就删除了所有访问权限。
再选“添加”-->“高级”-->“立即查找”,选中你的用户,例administrator,点“确定",“确定"。
来到权限项目窗口,勾选“完全控制”,点“确定”,OK了。
官方的提示:
Thepasswordfileshouldberead-onlyandonlyaccessiblebytheoperatingsystemuserTomcatisrunningas.
③■ 重新启动Tomcat,在Windows命令行输入“netstat-a”查看配置的端口号是否已打开,如果打开,说明上面的配置成功了。
④■ 使用jconsole测试JMX。
运行$JAVA_HOME/bin目录下的jconsole.exe,打开J2SE监视和管理控制台,然后建立连接,如果是本地的Tomcat则直接选择然后点击连接,如果是远程的,则进入远程选项卡,填写地址、端口号、用户名、口令即可连接。
Mbean属性页中给出了相应的数据,Catalina中是tomcat的,java.lang是jvm的。
对于加粗的黑体属性值,需双击一下才可看内容。
使用JMX监控Tomcat示例代码
StringjmxURL="service:
jmx:
rmi:
///jndi/rmi:
//192.168.10.93:
8999/jmxrmi";
JMXServiceURLserviceURL=newJMXServiceURL(jmxURL);
Mapmap=newHashMap();
//用户名密码,在jmxremote.password文件中查看
String[]credentials=newString[]{"monitorRole","tomcat"};
map.put("jmx.remote.credentials",credentials);
JMXConnectorconnector=JMXConnectorFactory.connect(serviceURL,map);
MBeanServerConnectionmbsc=connector.getMBeanServerConnection();
//端口最好是动态取得
ObjectNamethreadObjName=newObjectName("Catalina:
type=ThreadPool,name=http-8080");
MBeanInfombInfo=mbsc.getMBeanInfo(threadObjName);
//tomcat的线程数对应的属性值
StringattrName="currentThreadCount";
MBeanAttributeInfo[]mbAttributes=mbInfo.getAttributes();
System.out.println("currentThreadCount:
"+mbsc.getAttribute(threadObjName,attrName));
完整的示例代码文件
importjava.lang.management.MemoryUsage;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.Formatter;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.Set;
importjavax.management.MBeanAttributeInfo;
importjavax.management.MBeanInfo;
importjavax.management.MBeanServerConnection;
importjavax.management.ObjectInstance;
importjavax.management.ObjectName;
importjavax.management.openmbean.CompositeDataSupport;
importjavax.management.remote.JMXConnector;
importjavax.management.remote.JMXConnectorFactory;
importjavax.management.remote.JMXServiceURL;
/**
*使用JMX监控Tomcat示例
*
*@author陳峰
*/
publicclassJMXTest{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
try{
StringjmxURL="service:
jmx:
rmi:
///jndi/rmi:
//127.0.0.1:
8999/jmxrmi";
JMXServiceURLserviceURL=newJMXServiceURL(jmxURL);
Mapmap=newHashMap();
String[]credentials=newString[]{"monitorRole","tomcat"};
map.put("jmx.remote.credentials",credentials);
JMXConnectorconnector=JMXConnectorFactory.connect(serviceURL,
map);
MBeanServerConnectionmbsc=connector.getMBeanServerConnection();
//端口最好是动态取得
ObjectNamethreadObjName=newObjectName(
"Catalina:
type=ThreadPool,name=http-8080");
MBeanInfombInfo=mbsc.getMBeanInfo(threadObjName);
StringattrName="currentThreadCount";//tomcat的线程数对应的属性值
MBeanAttributeInfo[]mbAttributes=mbInfo.getAttributes();
System.out.println("currentThreadCount:
"
+mbsc.getAttribute(threadObjName,attrName));
//heap
for(intj=0;jSystem.out.println("###########"+mbsc.getDomains()[j]);
}
SetMBeanset=mbsc.queryMBeans(null,null);
System.out.println("MBeanset.size():
"+MBeanset.size());
IteratorMBeansetIterator=MBeanset.iterator();
while(MBeansetIterator.hasNext()){
ObjectInstanceobjectInstance=(ObjectInstance)MBeansetIterator
.next();
ObjectNameobjectName=objectInstance.getObjectName();
StringcanonicalName=objectName.getCanonicalName();
System.out.println("canonicalName:
"+canonicalName);
if(canonicalName
.equals("Catalina:
host=localhost,type=Cluster")){
//GetdetailsofclusterMBeans
System.out.println("ClusterMBeansDetails:
");
System.out
.println("=========================================");
//getMBeansDetails(canonicalName);
Stringcanon