通过Nagios监控Tomcat服务

 

 1.前言

本文主要介绍如何通过Nagios软件来监控Tomcat服务运行状况,其中主要包括Tomcat Server以及JDBC Pool的运行状态。Nagios的插件中本身并不提供对于Tomcat服务监控的功能,所以要根据Nagios PluginAPI编写自己的脚本,扩展其插件,完成我们所需要的功能。对于Tomcat运行状态信息的获得需通过JMX。

本文参考了Nagios3的官方文档中有关Nagios Plugin部分,以及Tomcat官方文档有关JMX和命令行部分,具体的Tomcat版本是7.0.81(JDK7)

 

 2.NagiosPlugin API概述

作为一个Nagios插件,无论你是用脚本(如shell、perl)还是用c编译后的可执行程序实现,它必须至少完成两件事,

1、退出时有一个返回值。

2、至少向标准输出设备(STDOUT)输出一行文本。

返回值定义:

Plugin Return Code

Service State

Host State

0

OK

UP

1

WARNING

UP or DOWN/UNREACHABLE*

2

CRITICAL

DOWN/UNREACHABLE

3

UNKNOWN

DOWN/UNREACHABLE

输出文本至少要一行,其信息主要反映被监控应用、服务的状态。

例如:DISK OK - free space: / 3326 MB (56%);

 

 3.监控Tomcat的实现方法

对于Tomcat运行状况的获得,我们是通过JMX访问Tomcat的方式实现的,通过JVM的queryMBeans方法查询获取具体的Mbean(Thread、JVM、JDBC),根据bean的属性值判断运行状态。

 3.1.     Tomcat开启RMI

通过JMX连接Tomcat,需开启Tomcat的RMI。开启需要指定具体端口,具体配置如下,需将如下代码加入Tomcat启动脚本。

export  JMX_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  

"

 

export  CATALINA_OPTS="$CATALINA_OPTS $JMX_REMOTE_CONFIG"

重启tomcat,并检查参数是否生效(通过ps –ef|grep java 查看参数是否已加入,通过netstat –lanp 查看端口是否启动)。

我们在这里选择了需要认证,并配置了访问控制文件。

-Dcom.sun.management.jmxremote.authenticate=true  

-Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password  

-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access  

登录用户monitorRole,权限readonly(只读)

cat  ../conf/jmxremote.access

monitorRole  readonly

登录用户monitorRole以及密码

cat  ../conf/jmxremote.password

monitorRole tomcat0930

 

 3.2.     通过JMX访问Tomcat

通过JMXConnectorFactory类,经JMX协议连接Tomcat的jmxrmi,注意这里需要进行认证。

String jmxURL = "service:jmx:rmi:///jndi/rmi://localhost:8999/jmxrmi";

JMXServiceURL serviceURL;

 

serviceURL = new JMXServiceURL(jmxURL);

 

Map map = new HashMap();

String[] credentials = new String[] {  "monitorRole", "XXXXX" };

map.put("jmx.remote.credentials",  credentials);

JMXConnector connector =  JMXConnectorFactory.connect(serviceURL,

                   map);

 

MBeanServerConnection mbsc =  connector.getMBeanServerConnection();

 

 

 3.3.     Tomcat运行状态信息获得

通过MBeanServerConnection获得具体的MBean。并通过MBean的属性获得运行状态。Thread、JVM、JDBC对应的属性获取方式具体如下。

Thread

        

                   ObjectName  ObjName = new ObjectName(

                                     "Catalina:name=\"http-bio-*\",type=ThreadPool");

 

                   Set  mbeanManagerSet = mbsc.queryNames(ObjName, null);

                   //  System.out.println("MBeanset1.size:" + MBeanset1.size());

                   System.out.println("#THREAD#");

                   for  (ObjectName obj : mbeanManagerSet) {

 

                            ObjectName  objectName = new ObjectName(obj.getCanonicalName());

 

                            String  canonicalName = objectName.getCanonicalName();

                            //  System.out.println("objectInstance : " + objectInstance);

                            System.out.println("+canonicalName  : " + canonicalName);

                            MBeanInfo  info = mbsc.getMBeanInfo(objectName);

                            MBeanAttributeInfo[]  ainfo = info.getAttributes();

 

                            //  逐一获得属性值

                            for  (int i = 0; i < ainfo.length; i++) {

 

                                     String  attributeName = ainfo[i].getName();

                                     String  attributeinfo = getAttributeByNmae(mbsc, objectName,

                                                        attributeName);

                                     if  (!("".equals(attributeinfo) || attributeinfo.isEmpty())) {

                                               System.out.println(attributeinfo);

                                     }

                            }

                            System.out.println("-canonicalName  : " + canonicalName);

                   }

         }

 

JVM

        

                   ObjectName  heapObjName = new ObjectName("java.lang:type=Memory");

                   MemoryUsage  heapMemoryUsage;

                   System.out.println("#JVM#");

                   System.out.println("+HeapMemoryUsage");

                   try  {

                            heapMemoryUsage  = MemoryUsage.from((CompositeDataSupport) mbsc

                                               .getAttribute(heapObjName,  "HeapMemoryUsage"));

 

                            long  maxMemory = heapMemoryUsage.getMax();// 堆最大

 

                            long  commitMemory = heapMemoryUsage.getCommitted();// 堆当前分配

 

                            long  usedMemory = heapMemoryUsage.getUsed();

                            System.out.println("    Max:" + maxMemory);

                            System.out.println("    Committed:" + commitMemory);// 堆当前分配

                            System.out.println("    HeapPercent:"

                                               +  (int) (usedMemory * 10000 / commitMemory) + "");// 堆使用率

                   }  catch (AttributeNotFoundException e) {

                            //  TODO Auto-generated catch block

                            //  e.printStackTrace();

                   }  catch (MBeanException e) {

                            // TODO Auto-generated catch block

                            //  e.printStackTrace();

                   }

                   System.out.println("-HeapMemoryUsage");

        

 

JDBC

        

                   //  获得javax.sql.DataSource信息

                   ObjectName  ObjName = new ObjectName(

                                     "Catalina:class=javax.sql.DataSource,context=/*,host=localhost,name=\"*\",type=DataSource");

 

                   Set  mbeanJDBCSet = mbsc.queryMBeans(ObjName, null);

                   //  System.out.println("MBeanset1.size:" + MBeanset1.size());

                   Iterator  MBeansetIterator1 = mbeanJDBCSet.iterator();

                   System.out.println("#JDBC#");

                   while  (MBeansetIterator1.hasNext()) {

                            ObjectInstance  objectInstance = (ObjectInstance) MBeansetIterator1

                                               .next();

                            ObjectName  objectName = objectInstance.getObjectName();

 

                            String  canonicalName = objectName.getCanonicalName();

                            //  System.out.println("objectInstance : " + objectInstance);

                            System.out.println("+canonicalName  : " + canonicalName);

                            MBeanInfo  info = mbsc.getMBeanInfo(objectName);

                            MBeanAttributeInfo[]  ainfo = info.getAttributes();

 

                            //  逐一获得属性值

                            for  (int i = 0; i < ainfo.length; i++) {

 

                                      String attributeName =  ainfo[i].getName();

                                     String  attributeinfo = getAttributeByNmae(mbsc, objectName,

                                                        attributeName);

                                     if  (!("".equals(attributeinfo) || attributeinfo.isEmpty())) {

                                               System.out.println(attributeinfo);

                                     }

                            }

                            System.out.println("-canonicalName  : " + canonicalName);

                   }

        

 

 

 3.4.     Nrpe Nagios Plugin

check_tomcat脚本逻辑如下(伪代码),

case "$v_cmd" in

--JVM)

        获取JVM信息

        如果获取出错,返回STATE_UNKNOWN状态

        如果HeapPercent大于crit,返回STATE_CRITICAL状态

如果HeapPercent大于crit,返回STATE_WARNING状态

返回STATE_OK状态

--JDBC)

        获取JDBC信息

         v_state_crit=0

         v_state_warn=0

        逐一处理JDBC

             如果maxActive小于等于numActive(活动数已经等于最大值),v_state_crit=1

             如果numActive大于0并且v_numIdle小于等于0(有活动且空闲数为零),v_state_warn=1

            

        如果v_state_crit=1,返回STATE_CRITICAL状态

如果v_state_warn=1,返回STATE_WARNING状态

返回STATE_OK状态

--THREAD)

        获取Thread信息

         v_state_crit=0

         v_state_warn=0

        逐一处理Thread

             如果maxConnections小于等于currentThreadCount(线程数已经等于最大值),v_state_crit=1

             如果currentThreadCount小于等于connectionCount(活动数已经达到线程数),v_state_warn=1

            

        如果v_state_crit=1,返回STATE_CRITICAL状态

如果v_state_warn=1,返回STATE_WARNING状态

返回STATE_OK状态

 

 3.5.     Nagios监控配置

Nrpe

./libexec下部署check_tomcat.sh脚本,并部署TomcatJMX.class到./libexec/tomcat/com/tomcat/jmx下。

./etc/nrpe.cfg

command[check_tomcat_JDBC]=/usr/local/nagios/libexec/check_tomcat.sh  --JDBC

command[check_tomcat_JVM]=/usr/local/nagios/libexec/check_tomcat.sh  --JVM 9998 9999

command[check_tomcat_THREAD]=/usr/local/nagios/libexec/check_tomcat.sh  --THREAD

 

Server

./etc/nagios.cfg

define service{

         use                      tomcat-service

         host_name               linux_XX

         service_description      check-wls-console--JDBC

         check_command            check_nrpe!check_tomcat_JDBC

        }

 

define service{

         use                      tomcat-service

         host_name               linux_XX

         service_description      check-wls-console--JVM

         check_command            check_nrpe!check_tomcat_JVM

        }

 

define service{

         use                      tomcat-service

         host_name               linux_XX

         service_description      check-wls-console--THREAD

         check_command            check_nrpe!check_tomcat_THREAD

        }

验证配置是否正确。

重启监控主机上的nagios服务以及远程主机上的nrpe服务。

通过IE观察监控情况。

wKiom1ne50uhAaIkAABQ3-C3sJ8940.png-wh_50

3.1


就此配置工作完成。

 4.结语

本文介绍了一种通过Nagios监控Tomcat应用的实现方式,按照Nagios Plugin API规则编写自己的Shell脚本实现该功能,并简单的描述了配置过程,提供了Shell源码。希望大家指正。