监控tomcat java框架_服务端tomcat的简单监控

本文介绍了监控Tomcat的两种方法:Tomcat-Manager和Psi-Probe,并详细讲解了如何配置和使用它们。此外,还讨论了通过JMX利用jconsole远程监控Tomcat的步骤,包括解决jstatd绑定问题和配置JMX参数。
摘要由CSDN通过智能技术生成

由于线上对tomcat监控处于失控的状态(只能通过跳转,简单地jstack/jstat进行监控),故需要针对tomcat快速查看其运行状态

Tomcat-manager

在tomcat/webapps中存在目录 manager,用于初步监控tomcat jvm相关参数指标。此时,用户需要手动编辑conf/tomcat-users.xml配置文件,加入一行:

用于声明可以进行管理tomcat的后端用户名和密码,此时就可以通过下面的url查看tomcat的整体服务状态,了解jvm堆的状态以及线程列表,并查看到所有的应用列表:

322121030b3e85639ded469fb607e409.png

但我们部署的tomcat都没有设置manager服务(webapps目录都已经将应用之外的目录删除掉了),而且其能够查看的指标也少的可怜。

Psi-Probe

项目源码所在地址:https://github.com/psi-probe/psi-probe,从github上clone下代码后,调用mvn clean package命令,进行编译,将生成的war包复制到需要监控的tomcat/webapps目录下,重新启动tomcat,生成的war包在目录./web/target/probe.war下。

psi-probe是lambdaprobe的一个分支版本,用于对Tomcat进行监控,比tomcat的manager强大很多。psi就是一个形如叉子的符号Ψ,希腊字母的第23个字母,用来代表fork。为啥需要分支呢,因为lambdaprobe已经多年没有更新(大致在2006年就停止发布新版本了)。

部署完成后,就可以通过 localhost:8080/probe 链接查看tomcat中的所有的相关信息:

c92a5cfdad4c23c46d9d24d901fea3ee.png

但是上述监控工具都不能针对java虚拟机中的具体类型进行细致的监控(针对我们定义的每个对象),我们需要找到一款可以检测tomcat内部的jmx客户端:http://stackoverflow.com/questions/5004958/web-based-jmx-console-for-tomcat

配置JMX使用jconsole监测远程tomcat

编写配置文件 jstatd.java.policy策略文件:

# cat jstatd.java.policy

grant codebase "file:${java.home}/../lib/tools.jar" {

permission java.security.AllPermission;

};

开启jstatd守护进程

jstatd -J-Djava.security.policy=/root/jstatd.all.policy -J-Djava.rmi.server.logCalls=true(开启日志功能)

jstatd -J-Djava.security.policy=jstatd.all.policy

Could not create remote object

access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")

java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")

at java.security.AccessControlContext.checkPermission(AccessControlContext.java:457)

at java.security.AccessController.checkPermission(AccessController.java:884)

at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)

at java.lang.System.setProperty(System.java:789)

at sun.tools.jstatd.Jstatd.main(Jstatd.java:139)

在启动tomcat的时候(修改执行tomcat的文件,catalina.sh),需要加入以下JVM参数:

-Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.1.165

说明:

1.-Dcom.sun.management.jmxremote.port:这个是配置远程connection的端口号的,要确定这个端口没有被占用;

2.-Dcom.sun.management.jmxremote.ssl=false 指定了 JMX 是否启用 ssl;

3.-Dcom.sun.management.jmxremote.authenticate=false指定了JMX 是否启用鉴权(需要用户名,密码鉴权),

2,3两个是固定配置,是 JMX的远程服务权限的;

4.-Djava.rmi.server.hostname:这个是配置server的IP的;

在CentOS环境中启动jstatd仍然出现错误,

Could not bind /JStatRemoteHost to RMI Registry

java.rmi.ConnectIOException: Exception creating connection to: 0.0.0.2; nested exception is:

java.net.SocketException: Invalid argument or cannot assign requested address

at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:631)

at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:216)

at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:202)

at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:341)

at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)

at java.rmi.Naming.rebind(Naming.java:177)

at sun.tools.jstatd.Jstatd.bind(Jstatd.java:57)

at sun.tools.jstatd.Jstatd.main(Jstatd.java:143)

Caused by: java.net.SocketException: Invalid argument or cannot assign requested address

at java.net.PlainSocketImpl.socketConnect(Native Method)

at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)

at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)

at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)

at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)

at java.net.Socket.connect(Socket.java:579)

at java.net.Socket.connect(Socket.java:528)

at java.net.Socket.(Socket.java:425)

at java.net.Socket.(Socket.java:208)

at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:40)

at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:147)

at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:613)

... 7 more

通过阅读下面的文档 http://my.oschina.net/xiaotian120/blog/207015,经过服务器上的一番调研,发现问题出现在hostname上,服务端调用 hostname -i 命令,显示出来的服务器主机名为0.0.0.2(这一点日志中有体现)。

如果需要手动设置密码,可以参考:http://wiki.jikexueyuan.com/project/tomcat/monitoring-management.html,来加入鉴权相关命令,编辑访问权限文件jmxremote.access, 以及密码文件jmxremote.password。

JMX监测程序中的某些行为

JMX是一个框架,提供了一种功能,可以实时查询应用程序中通过JMX向外部公布的相应参数或者是其他应用程序,同时也可以通过JMX来实时地调用应用程序使用JMX向外部公布的接口,来完成一些功能操作。

我们还是从JMX能给我们提供什么好处入手来理解吧。举一个应用实例:在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来写这些代码呢?

1、初级程序员一般是写死在程序里,到要改变时就去改程序,然后再编译发布;

2、程序熟手则一般把这些信息写在一个配置文件里(JAVA一般都是*.properties文件),到要改变时只要改配置文件,但还是重新启动系统,以便读取配置文件里的新值;

3、程序好手则会写一个段代码,把配置值缓存起来,系统在读值的时候,先看看配置文件有 没有更动。如有更改则重读一遍,否则从缓存里读取值

4、程序高手则懂得取物为我所用,用JMX!把配置属性集中在一个类,然后写一个叫MBean的东东,再配置一下就轻松搞定了。而且JMX自动提供了一个WEB页面来给你来改变这些配置信息。

16a3b5a3b5daec824bc2016306cf8cc5.png

通过JMX可以轻松地为应用程序添加管理功能,在尽可能少的改变原有系统代码基础上实现对原系统的管理。

概念

含义

Managable resource

可被管理的资源可以是应用程序,设备或者存在的能够被java程序所访问或者包装的实体。通过JMX可以管理这些资源。应用程序能够暴露自己的组件,API或者附加的资源,使得JMX能够管理应用程序。可被管理的资源甚至可以是网络上的设备,例如打印机。可被管理的资源作为一个实体被JMX MBean所管理。

MBean

MBean(managed bean)是一个Java类,符合JMX specification所规定的命名和继承规范。实例化的MBeans是Java对象,其中所暴露出来的接口(management interface)能够操作和访问manageable resources。这些接口是由MBean的属性和操作组成。

Management application通过访问MBean来访问属性和调用操作。MBean分三种类型:Standard,Dynamic和Model MBean.每一种类型都是针对于特定的manageable resource来使用的。

JMX Agent

JMX agent是一个Java process,能够为管理MBean的集合提供服务,是MBean Server的容器。这些服务可以是建立MBean的之间的关系,动态加载类,监控服务,作为计时器。

Management application

一个management application可以是任何的用户程序,用于和任意多的JMX agent之间建立接口。对于一些设计好的符合JMX技术的management appliction,JMX agents能够建立和该management application的联系,JMX agents也能够建立和那些先前没有考虑用JMX技术的management application建立联系。

传输和安全性

JMX 指定了在 MBeanServer 和 JMX 客户之间通信所使用的协议,协议可以在各种传输机制上运行。可以使用针对本地连接的内置传输,及通过 RMI、socket 或 SSL 的远程传输(可以通过 JMX Connector API 创建新的传输)。认证是由传输执行的;本地传输允许用相同的用户 ID 连接到运行在本地系统上的 JVM;远程传输可以用口令或证书进行认证。本地传输在 Java 6 下默认就是启用的。要在 Java 5.0 下启用它,需要在 JVM 启动时定义系统属性 com.sun.management.jmxremote。“Monitoring and Management using JMX” 这份文档(请参阅参考资料)描述了启用和配置传输的配置步骤。

新建第一个MXBean

注册时使用MBeanServer进行注册的操作,给定对应的mbean,mbeanServer会根据该bean实现的接口去寻找其对应的MBean定义。

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

ControllerMBean controllerMBean = new ControllerBean();

mbs.registerMBean(controllerMBean, new ObjectName("MyAppmbean:name=controller"));

出现问题

javax.management.NotCompliantMBeanException: jmx.ControllerBean: Class jmx.ControllerBean is not a JMX compliant MXBean

at com.sun.jmx.mbeanserver.Introspector.throwException(Introspector.java:466)

at com.sun.jmx.mbeanserver.Introspector.getMXBeanInterface(Introspector.java:357)

at com.sun.jmx.mbeanserver.Introspector.checkCompliance(Introspector.java:166)

at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:317)

at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)

at jmx.Main.main(Main.java:16)

经过分析JMX.isMXBeanInterface方法,可以看出,在registerMBean的时候,会根据当前类实现的接口列表,查找符合MXBean定义的接口,如果接口不符合MXBean的定义就会抛出上面的错误,如何使得接口满足MXBean类型,一种是接口名称以“MXBean”结尾,一种是加入@MXBean Annotation。

public static boolean isMXBeanInterface(Class> interfaceClass) {

if (!interfaceClass.isInterface())

return false;

if (!Modifier.isPublic(interfaceClass.getModifiers()) &&

!Introspector.ALLOW_NONPUBLIC_MBEAN) {

return false;

}

MXBean a = interfaceClass.getAnnotation(MXBean.class);

if (a != null)

return a.value();

return interfaceClass.getName().endsWith("MXBean");

// We don't bother excluding the case where the name is

// exactly the string "MXBean" since that would mean there

// was no package name, which is pretty unlikely in practice.

}

Spring与JMX的整合

对于标准的MBean来说,主要是通过MBeanExporter来实现的,比如上面我们提到的MBean,就可以通过配置mbServer以及mbean的方式管理MXBean:

上面的配置中,MBeanExporter会查找本地MBean Server,指定的探测模式autodetectModeName为AUTODETECT_ALL,无需手动向MBean Server进行注册,便可以管理配置中的MBean对象。

基于注解的MBean管理

@ManagedResource表示指定该类的实例作为MBean注册到MBean Server中,然后通过对属性和方法分别使用@ManagedAttribute和@ManagedOperation来指定暴露的属性和方法,

@Component

@ManagedResource(objectName = "org.springexample.jmx:name=ServerManager", description = "Server Manager")

public class ServerManagerImpl {

private String serverName = "springServer";

private boolean serverRunning = true;

private int minPoolSize = 5;

private int maxPoolSize = 10;

@ManagedAttribute(description = "The server name.")

public String getServerName() {

return serverName;

}

@ManagedAttribute(description = "Server's running status.")

public boolean isServerRunning() {

return serverRunning;

}

@ManagedAttribute(description = "Whether or not the server is running.", currencyTimeLimit = 20, persistPolicy = "OnUpdate")

public void setServerRunning(boolean serverRunning) {

this.serverRunning = serverRunning;

}

@ManagedOperation(description = "Change db connection pool size.")

@ManagedOperationParameters({

@ManagedOperationParameter(name = "min", description = "Minimum pool size."),

@ManagedOperationParameter(name = "max", description = "Maximum pool size.")

})

public int changeConnectionPoolSize(int minPoolSize, int maxPoolSize) {

Assert.isTrue(minPoolSize > 0, "Minimum connection pool size must be larger than 0, min=" + minPoolSize);

Assert.isTrue(maxPoolSize > minPoolSize, String.format("Minimum connection pool size must be smaller than maximum, min=%s, max=%s", minPoolSize, maxPoolSize));

this.minPoolSize = minPoolSize;

this.maxPoolSize = maxPoolSize;

int diff = maxPoolSize - minPoolSize;

Random random = new Random();

int currentSize = (minPoolSize + random.nextInt(diff));

return currentSize;

}

}

基于spring基于注解的MBean管理可以针对一个普通的Java类,指定暴露的属性和方法,此时在spring applicationContext中声明的内容就要少很多,只需要声明扫描的package,以及mbean-export即可。

示例中我们就可以简单地动态修改类似池话的一些配置资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值