锁定老帖子 主题:运用JMX远程监控、管理JVM(一)
精华帖 (3) :: 良好帖 (2) :: 新手帖 (1) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-10-29
最后修改:2011-10-29
问题背景讨论:在JAVA运行时,对JVM系统的检测、管理是开发同学一直期望的,目前有一些开源产品开源针对JVM进行监控,例如javamelody等等,这样框架虽然好,但是如果使用会带来一些问题。第一:由于javamelody入口是一个filter,所以会带来性能问题、第二:如果应用服务器很多,会缺乏统一管理,此外安全性、爬虫等等问题略过不提
JDK自带了故障检测工具Jconsole和1.6出来的Jvisualvm都可以远程对服务器进行监控,后者甚是提供可以在线得到ThreadDump和HeapDump文件,更是提供了可扩展插件功能(虽然可能会影响jvm服务器性能) 但现状很多公司都有自己的运维团队,未必会把线上服务器的权限交给我们开发同学,所以有必要了解JAVA远程管理方面的知识,假设如果在后台有一套系统,可以管理、监控我们线上所有java服务器,如果出现问题不需要对每个服务器进行排查而是直接从列表中获取、定位到信息,岂不是一件很幸福的事情~ 书归正文,分享下近几天在JMX方面的知识,JDK的API中翻译过来对javax.management的描述 提供 Java Management Extensions 的核心类。 Java Management Extensions (JMXTM) API 是一个用于管理和监视的标准 API。典型用途包括: 1) 查询并更改应用程序配置 2) 累积有关应用程序行为的统计数据并使其可用 3) 通知状态更改及错误状况。 4) JMX API 还可以作为解决方案的一部分来管理系统、网络等。 5) API 包括远程访问,远程管理程序可以基于这些目的与正在运行的应用程序进行交互。 JMX核心类为Mbean。MBean 是表示资源的指定管理对象。它有一个管理接口,该接口包括以下内容: 1) 可以读取和/或写入的指定名称和类型的属性 2) 可以调用的指定名称和类型的操作 3) 可以由 MBean 发送的指定类型的通知。 推荐一篇文章可以让大家入门 http://www.ibm.com/developerworks/cn/java/j-lo-jse63/ 配置远程连接tomcat需要在tomcat所在服务器修改几个配置 1) 修改JMX配置 进入JAVA_HOME/jre/lib/management路径下面 将jmxremote.password.template改成jmxremote.password,将内容中的monitorRole QED的注释去掉 将management.properties中的com.sun.management.jmxremote.port=(改成你想要的JMX端口号) 将 com.sun.management.jmxremote.ssl=false、 com.sun.management.jmxremote.authenticate=false注释打开 注意:linux下需要该权限,chmod 600 jmxremote.access, chmod 600 jmxremote.password window下特麻烦,现需要jdk装在NTFS文件系统下,选中文件,点右键“属性”-〉安全,点“高级”,去掉“从父项继承....”,弹出窗口中选“删除”,这样删除了所有访问权限。再选“添加”-〉高级,“立即查找”,选中你的用户,例administrator,点“确定",“确定"。来到权限窗口,勾选"完全控制",点"确定",OK了。 用jconsole连接远程linux服务时, IP地址和port都输入正确的情况下,仍然是连接失败 vi /etc/hosts,将hostname对应的ip改为真实ip 2) 修改tomcat启动参数 windows下面为catalina.bat、linux下面为cataina.sh set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port="JMXport" -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false 如果不修改的时候默远程连接不上,远程连接的通过IP和JMX端口找到JVM虚拟机后无法定位具体哪个应用使用JMX端口,所以只有在启动tomcat情况后占用JMX 关于配置JMX,可以具体参考http://download.oracle.com/javase/1.5.0/docs/guide/management/agent.html#remote 实战远程连接TOMCAT 1) 获取连接 private static void getConnection() throws Exception { //用户名、密码 Map<String, String[]> map = new HashMap<String, String[]>(); map .put("jmx.remote.credentials", new String[] { "monitorRole", "QED" }); String jmxURL = "service:jmx:rmi:///jndi/rmi://192.168.0.100:1000/jmxrmi"; JMXServiceURL serviceURL = new JMXServiceURL(jmxURL); connector = JMXConnectorFactory.connect(serviceURL, map); mbsc = connector.getMBeanServerConnection(); } 2) 获取所有的objectName Set MBeanset = mbsc.queryMBeans(null, null); Iterator MBeansetIterator = MBeanset.iterator(); while (MBeansetIterator.hasNext()) { ObjectInstance objectInstance = (ObjectInstance) MBeansetIterator .next(); ObjectName objectName = objectInstance.getObjectName(); MBeanInfo objectInfo = mbsc.getMBeanInfo(objectName); System.out.print("ObjectName:" + objectName.getCanonicalName() + "."); System.out.print("mehtodName:"); for (int i = 0; i < objectInfo.getAttributes().length; i++) { System.out.print(objectInfo.getAttributes()[i].getName() + ","); } System.out.println(); } 3) 获取堆内存信息 ObjectName heapObjName = new ObjectName("java.lang:type=Memory"); //堆内存 MemoryUsage heapMemoryUsage = MemoryUsage .from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "HeapMemoryUsage")); long commitMemory = heapMemoryUsage.getCommitted();// 堆当前分配 long usedMemory = heapMemoryUsage.getUsed(); System.out.print("堆内存总量:"+heapMemoryUsage.getMax()/1024+"KB,当前分配量:"+commitMemory/1024+"KB,当前使用率:"+usedMemory/1024+"KB,"); System.out.println("堆内存使用率:" + (int) usedMemory * 100 / commitMemory + "%");// 堆使用率 //栈内存 MemoryUsage nonheapMemoryUsage = MemoryUsage .from((CompositeDataSupport) mbsc.getAttribute(heapObjName, "NonHeapMemoryUsage")); long noncommitMemory = nonheapMemoryUsage.getCommitted(); long nonusedMemory = heapMemoryUsage.getUsed(); System.out.println("栈内存使用率:" + (int) nonusedMemory * 100 / noncommitMemory + "%"); //PermGen内存 ObjectName permObjName = new ObjectName( "java.lang:type=MemoryPool,name=Perm Gen"); MemoryUsage permGenUsage = MemoryUsage .from((CompositeDataSupport) mbsc.getAttribute(permObjName, "Usage")); long committed = permGenUsage.getCommitted();// 持久堆大小 long used = heapMemoryUsage.getUsed();// System.out.println("perm gen:" + (int) used * 100 / committed + "%");// 持久堆使用率 4) 获取堆中伊甸区 ObjectName youngHeapObjName = new ObjectName("java.lang:type=MemoryPool,name=Eden Space"); // 获取Mbean对象 MBeanInfo youngHeapInfo = mbsc.getMBeanInfo(youngHeapObjName); // 获取对象的属性 MBeanAttributeInfo[] youngHeapAttributes = youngHeapInfo.getAttributes(); MemoryUsage youngHeapUsage = MemoryUsage .from((CompositeDataSupport) mbsc.getAttribute(youngHeapObjName, "Usage")); System.out.print("目前新生区分 配最大内存:"+youngHeapUsage.getMax()/1024+"KB,"); System.out.print("新生区已分配:"+youngHeapUsage.getCommitted()/1024+"KB,"); System.out.print("新生区初始化:"+youngHeapUsage.getInit()/1024+"KB,"); System.out.println("新生区已使用"+youngHeapUsage.getUsed()/1024+"KB"); 5) 获取线程 ObjectName managerObjName = new ObjectName( "Catalina:type=Manager,*"); Set<ObjectName> s = mbsc.queryNames(managerObjName, null); for (ObjectName obj : s) { ObjectName objname = new ObjectName(obj.getCanonicalName()); System.out.print("objectName:"+objname); System.out.print(",最大会话数:" + mbsc.getAttribute(objname, "maxActiveSessions")+","); System.out.print("会话数:" + mbsc.getAttribute(objname, "activeSessions")+","); System.out.println("活动会话数:" + mbsc.getAttribute(objname, "sessionCounter")); 由于可以获取的信息很多,暂不全部列出来 翻过头来看下tomcat对JMX的支持 看完上面最后一段话,有没有一种很雷人的感觉 关于tomcat对JMX的支持可以看下详细的文档 http://tomcat.apache.org/tomcat-6.0-doc/monitoring.html 当我们默认直接访问tomcat提供的JMX接口时(http://localhost:8080/manager/jmxproxy/?qry=)会出现所有的MBeans, 如果想要具体的MBeans只需要将其name后面的值放在url的后面 因此,在默认情况下我们看到的信息都可以通过远程方式获取到,下一篇会介绍如何远程管理Tomcat 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-10-29
不错。写的很全面。因为我们程序一直跑在服务器上,所以最好的监控办法是用定时器的方式把JVM相关信息打印出来,然后记录在相关的LOG里面,但对JVM相关信息抓取时,会给服务器造成一些压力,特别是在服务器压务大的时候,此外,其实服务器平常负载较低时的一些JVM信息没有太大必要,一般情况是出现问题时的JVM信息最有价值,更有利于解决问题,所以可以用定时器的方法,每一段时间去尝试着抓一次JVM信息,抓信息之前啄不判断一下系统负载,只有高于某个值的时候才去抓,此外,是否可以考虑,当某种情况下,通过发送邮件等方系提醒管理人员,说你的某个JVM值异常,这样可能会提前预知某些线上的问题,减少对用户带来的体验,这样你的这些研究就更有价值了。一步一步来吧。
用JAVA程序的方式去获取这些JVM信息,很不错(向JAVA提供的那些JAVA指令,jstack, jconsole, jinfo, jmap...也是调用的java tools.jar 里面的工具类,因为CYOU对程序人员的线上某些限制,所以用这种办法去解决,非常不错。)。争取把这些结合现有的资源来实现服务器的监控。 |
|
返回顶楼 | |
发表时间:2011-10-29
dxm1986 写道 不错。写的很全面。因为我们程序一直跑在服务器上,所以最好的监控办法是用定时器的方式把JVM相关信息打印出来,然后记录在相关的LOG里面,但对JVM相关信息抓取时,会给服务器造成一些压力,特别是在服务器压务大的时候,此外,其实服务器平常负载较低时的一些JVM信息没有太大必要,一般情况是出现问题时的JVM信息最有价值,更有利于解决问题,所以可以用定时器的方法,每一段时间去尝试着抓一次JVM信息,抓信息之前啄不判断一下系统负载,只有高于某个值的时候才去抓,此外,是否可以考虑,当某种情况下,通过发送邮件等方系提醒管理人员,说你的某个JVM值异常,这样可能会提前预知某些线上的问题,减少对用户带来的体验,这样你的这些研究就更有价值了。一步一步来吧。
用JAVA程序的方式去获取这些JVM信息,很不错(向JAVA提供的那些JAVA指令,jstack, jconsole, jinfo, jmap...也是调用的java tools.jar 里面的工具类,因为CYOU对程序人员的线上某些限制,所以用这种办法去解决,非常不错。)。争取把这些结合现有的资源来实现服务器的监控。 嗯..嘿嘿,你早上起的也蛮早的啊~ 系统负载较高的情况下发送邮件、警报这类功能之前也想过,眼下可以实现的是对系统资源的监控并警报,至于JVM 相关现在很难权衡“瓶颈点”,只能以后有更多经验了一步步完善,和kaihong讨论过几次,以后tomcat监控只是监控系统中的一部分,你上面说的远程抓取GC日志还没有想过呢~可以单独提出来想下哈..嘻嘻~ |
|
返回顶楼 | |
发表时间:2011-10-31
Java 就是复杂,搞得好麻烦
|
|
返回顶楼 | |
发表时间:2011-10-31
netkiller.github.com 写道 Java 就是复杂,搞得好麻烦
哦,呵呵 |
|
返回顶楼 | |
发表时间:2011-11-01
我按照上面的步骤配置后,连接报连接被拒绝,而且用jConsole远程连接也一样,但是如果用Jconsole本地连接后,再远程连接或是用代码就可以了,不知道是哪里的问题,多谢!
|
|
返回顶楼 | |
发表时间:2011-11-01
有一个问题请教LZ,如果tomcat已经配置打开了jmx端口,那我直接用jconsole或者jvisualvm不就能连上了吗?自己开发一套代码的目的何在呢?
|
|
返回顶楼 | |
发表时间:2011-11-01
zhupan 写道 我按照上面的步骤配置后,连接报连接被拒绝,而且用jConsole远程连接也一样,但是如果用Jconsole本地连接后,再远程连接或是用代码就可以了,不知道是哪里的问题,多谢!
服务器的操作系统是什么? 如果是先连接本地之后在连接就可以,说明你没有配置成功Tomcat启动参数,默认情况下JMX端口号不会被占用,如果在Catalina.sh(bat)加上下面参数就可以成功,前提是“JMXport要和你配置的一样” 引用 set CATALINA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port="JMXport" -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false |
|
返回顶楼 | |
发表时间:2011-11-01
kyfxbl 写道 有一个问题请教LZ,如果tomcat已经配置打开了jmx端口,那我直接用jconsole或者jvisualvm不就能连上了吗?自己开发一套代码的目的何在呢?
这个兄弟问题非常好,不知道你那面线上环境如何,但是一些服务器很多的项目涉及到一个统一管理的问题,前面是LVS或者NGINX等负载均衡服务器、后面是缓存服务器、应用服务器,再往后就是各种数据源(包括关系数据库、NOSQL库、Solr等等)而针对类似Tomcat等应用服务器监控管理只是其中的一部分。 |
|
返回顶楼 | |
发表时间:2011-11-01
用jdk的jconsle是不是会更方便些,也能jmx远程
|
|
返回顶楼 | |