使用 JMX 接口来编写 PMI 应用程序

来源:互联网 发布:云淘网络 编辑:程序博客网 时间:2024/05/16 01:56

本文解释了 PMI、JMX MBeans 和 J2EE 管理规范所定义的性能数据框架(Performance DataFramework)之间的关系,并向您展示如何使用 JMX 接口来访问 WebSphere Application Server PMI 数据。

引言


为了帮助识别性能问题及调优运行 Web 应用程序的环境,IBM® WebSphere® Application Server收集性能数据并提供接口来让外部的应用程序监控这些性能数据。数据是通过性能监控基础设施(Performance MonitoringInfrastructure,PMI)收集在 WebSphere Application Server 和客户应用程序中的,然后 PMI数据通过不同的接口向用户公开。

目前有三种 PMI 数据接口可用:

  • PMI客户机
  • 性能 servlet
  • Java™ Management Extension (JMX)接口。

PMI 客户机和 servlet 接口在 WebSphere Application Server V4 和 V5 中可用。JMX 接口是 WebSphereApplication Server V5 新增的一个接口。

WebSphere Application Server包含了一个基本的浏览器 -- Tivoli® Performance Viewer(TPV)-- 来查看 PMI 数据,用户可以用它来查看 PMI 计数器的各种图表和值。也有许多使用这些 PMI 接口的第三方工具,可以可以通过它们来识别PMI 计数器的极限值并帮助客户分析 Web 站点什么时候有性能问题。

本文解释了 PMI、JMX MBeans 和 J2EE管理规范所定义的性能数据框架之间的关系(请参阅 参考资料)。我们将要讨论如何使用JMX 接口来访问 WebSphere Application Server PMI 数据,其中包括如何实例化一个 AdminClient实例、如何得到进行 PMI 访问所需的 JMX MBeans、如何设置 PMI 装备级别,以及如何获取 PMI 数据等内容。同时还包括一个使用 JMX接口收集 PMI 数据的 可下载样本程序。

什么是 PMI ?

Performance Monitoring Infrastructure 是 WebSphere Application Server中的一个底层框架,它从不同的运行时资源(如 JVM 和 Thread Pool)和应用程序组件(如 servlet 和 Enterprise JavaBeans(EJBs))收集性能数据。一些可用的 WebSphere Application Server V5 计数器的例子包括:

  • 平均响应时间
  • 总请求数
  • 线程池大小
  • JVM 堆大小。

PMI从服务器的不同组件收集这些数据并将它们组织成一个树状结构。图 1 是 Tivoli Performance Viewer中的一个快照,它显示了这个以服务器为根的树状结构,其中与服务器直连的树节点称为 PMI模块(用红圈标出),模块之下的树节点称为子模块,子模块下还可有子模块,以此类推。

每个 PMI 模块和子模块都包含从相应的 WebSphere 组件中收集的 PMI数据列表。一些模块和子模块是从运行时实体收集数据的,另一些聚集来自这些运行时实体的数据。例如,PMI 为各种线程池(如 Object RequestBroker (ORB)和 Web 容器线程池)提供数据,并聚集单个线程池的数据。这些 PMI 数据用以下的树状层次来组织:

线程池模块=>聚集所有线程池的数据的模块....ORB 线程池=>用于处理收集在 ORB 线程池中的数据的子模块.... Web 容器线程池=>用于处理收集在 Web 容器线程池中的数据的子模块.... 其他线程池(如果还有的话)  
图 1. 来自 TPV 快照的 PMI 模块/子模块树状结构
Figure 1. The PMI module/submodule tree structure from a TPV snapshot

用户通过监控工具,如 Tivoli Performance Viewer(这是 WebSphere Application Server所附带的,以前称为 Resource Analyzer)和第三方工具检索 PMI 数据。用户也可以使用可编程接口(如 PMI 客户机和 JMXAPI)来编写自己的 PMI 应用程序。WebSphere Application Server V5 新增的一个服务器管理模块接口 -- JMX接口 -- 允许通过 JMX MBeans 来远程访问数据。

以下的部分我们将会介绍 PMI、J2EE 性能数据框架和 JMX MBeans的关系,然后分步介绍如何使用 JMX 接口来发现 MBeans、如何设置装备级别以及如何得到 PMI 数据。(请参阅 参考资料以获取关于PMI 客户机 API 的信息。)

PMI、J2EE性能数据框架和 JMX MBeans


在 WebSphere Application Server V5 中,PMI 不仅为应用服务器中的各种组件提供性能数据,同时也实现了由 J2EE管理规范中的性能数据框架定义的统计接口。这些统计接口包括以下的数据类型:

  • CountStatistic
  • TimeStatistic
  • RangeStatistic
  • BoundedRangeStatistic.

系统还定义了 Stats 接口来包含统计数据列表。

PMI 实现了这些统计接口,更新各种统计数据并通过不同的接口公开这些数据。在 WebSphereApplication Server V4 中,PMI 提供了定义 CpdLong、CpdStat 和 CpdLoad 数据类型的 PMI客户机接口。(这些接口仍然支持向后兼容。)表 1 逐条描述了用于版本 5 中的数据类型的 API。请注意,PMI 数据中的 API 扩展了 J2EE性能数据框架里的定义,用 * 来标志这些由 PMI 扩展的 API。

表 1. 不同的 PMI 数据类型和 API

5.0类型对应 4.0的类型描述APICountStatisticCpdLong保持单一的当前值getCount()TimeStatisticCpdStat保持总数、个数、最小值和最大值。均值可由总数与个数相除得到。getTotalTime() 
getCount() 
getMean() 
getMinTime() 
getMaxTime() 
getTimeOfSquares()*RangeStatisticCpdLoad保持当前值、最小值、最大值和以时间衡量的总数,由它可以得到平均值。getCurrent() 
getLowWaterMark() 
getHighWaterMark() 
getIntegral()* 
getMean()* BoundedRangeStatisticCpdLoad保持当前值、最小值、最大值、下限、上限和以时间衡量的总数,由它可以得到平均值。getCurrent() 
getLowWaterMark() 
getHighWaterMark() 
getIntegral()* 
getMean()* 
getLowerBound() 
getUpperBound() StatsCpdCollection保持统计数据列表,也可选择性保持来自其子模块的 Stats 对象列表。getStatistic(int dataId)* 
getStatistic(String name) 
getStatistics() 
getStatisticNames() 
getSubStats()* 

每个 PMI 数据类型都有随时间刷新的动态值和不变的静态配置信息。动态值包含当前值、最小值、最大值、总数等等。静态信息包括名称、单元和数据描述。表1 示出了返回动态值给不同类型的数据的 API。每个数据类型也都有返回静态信息给每个数据的公共 API。这些 API 包括:

  • getName: 返回数据名称
  • getUnit:返回数据单元
  • getDescription:返回数据描述

PMI 数据可以通过不同的接口进行访问,包括 JMX 接口。JMX 体系结构是一个标准的管理模块,受管 Bean(Managed Bean,MBean)就是在该模块中管理业务应用程序和资源的。MBean可以是一个统计提供者,它为受管理的应用程序和资源提供各种统计数据。PMI 为作为统计提供者的 MBean 实现和刷新统计数据(也就是 PMI数据)。这些 PMI 数据可以在客户端通过 JMX 接口进行检索。

如果某一 MBean 是一个统计提供者,那么它的 PMI统计数据可以使用 Stats 属性从 MBean 进行检索。在 WebSphere Application Server V5 中有几个 MBean提供了 Stats 属性。请查看 WebSphere Application Server Information Center(在Performance => Monitoring Performance => Performance data organization中),其中有这种 MBean 类型的列表。

PMI 服务和 PerfMBean体系结构


在 WebSphere Application Server V5 中,PMI服务在每个应用服务器和节点代理进程中都可用。在获取 PMI 数据之前首先应该启用 PMI 服务,您可以通过管理控制台或用管理脚本来启用 PMI服务。在这两种情况下,应用服务器都必须重启。在 Network Deployment 环境中,PMI 服务可以在应用服务器或 NodeAgent 中启用。

系统实现了一个名为“PerfMBean”的 MBean 来配置 PMI 服务(也就是设置装备级别),并且提供 API 来通过一次 JMX 调用从多个MBean收集 PMI 数据,而不是使用各种 MBean 的。图 2 是 PMI 体系结构的一个简化的视图。PerfMBean API 或各种 MBeanAPI 都提供 PMI 统计数据,但只有 PerfMBean 这个 MBean 能够设置装备级别。PerfMBean 还可以通过一次 JMX调用处理多个 MBean 来减少远程 JMX 调用的次数。

图 2. PMI数据访问的高级视图
Figure 2. High level view of PMI data access

表 2 归纳了如何使用 PerfMBean 和各种 MBean 来配置和访问 PMI 数据。由于 PerfMBean 提供了比 MBean更广泛和更有效的功能,所以通常用它来开发监控工具。

表 2. 不同的 PMI 数据类型和 API

MBean设置装备级别从单个 MBean 中获取 PMI 数据从多个 MBean 中获取 PMI 数据从没有 MBean 的 PMI 模块和子模块获取 PMI 数据获取静态配置信息PerfMBeanYesYesYesYesYesIndividualMBeansNoYesNoNoNo

既然我们已经讨论了 PMI 数据、JMX、PerfMBean 和各种 MBean 之间的关系,现在我们就来看看如何使用 JMX 接口来获取 PMI数据。

如何通过 JMX 接口获取 PMI 数据


下面通过一些样本代码来说明通过 JMX 接口获取 PMI 数据的步骤。这些步骤包括:

  1. 创建一个 AdminClient 实例
  2. 查找 PerfMBean 和各种 MBean
  3. 设置装备级别
  4. 从单个 MBean 中获取 PMI 数据
  5. 从多个MBeanStatDescriptor 获取 PMI 数据
  6. 检索静态配置信息
  7. 从 Stats 对象获取各种 PMI 计数器。

步骤 1:创建一个 AdminClient 实例


在 WebSphereApplication Server V5 中,所有的远程 JMX 调用都是通过 AdminClient 接口实现的,该接口通过代理提供客户端 API给 JMX 客户机并代发所有的调用给服务器端的 JMX 连接器。当前支持的连接器是 SOAP 和 RMI 连接器。

您需要通过合适的主机名、端口号和连接器类型才能创建 AdminClient 实例。以下的代码样本创建一个名为“ac”的 AdminClient实例,在后面的步骤中会用它来查询 JMX、从 MBean 获取 Stats,以及调用 MBean 中的方法。

AdminClient ac = null;java.util.Properties props = new java.util.Properties();props.put(AdminClient.CONNECTOR_TYPE,connector);props.put(AdminClient.CONNECTOR_HOST,host);props.put(AdminClient.CONNECTOR_PORT,port);try { ac = AdminClientFactory.createAdminClient(props);} catch (ConnectorException ex) { System.out.println("Exception to create AdminClient: " + ex);}

步骤 2:查找 PerfMBean 和各种 MBean


每个 MBean 都有一个 ObjectName,在使用该 MBean之前必须先找到它。ObjectName 可以通过 AdminClient,以格式化的查询串进行查询。格式化的查询串可以选择性地包括以下的特性:域名、节点名、进程名、类型、名称等等。一个查询串既可惟一标识单个ObjectName,也可以代表多个具有公共特性的 ObjectName。MBean 通常是以它们的类型进行分类的。

如果 PMI服务在某一应用服务器上可用,那么在该服务器上有且仅有一个类型为“Perf”的 MBean (PerfMBean),它为 PMI 服务配置和 PMI数据恢复提供了扩展的功能。以下的代码将会返回服务器中的 PerfMBean 的 MBean ObjectName。

StringBuffer oNameQuery= new StringBuffer();   // "Perf" can be replaced by other types to find MBeans in those typesString domainName = ac.getDomainName();oNameQuery.append(domainName).append(":*");oNameQuery.append(",type=").append("Perf");oNameQuery.append(",node=").append(mynode); oNameQuery.append(",process=").append(myserver); Set oSet= ac.queryNames(new ObjectName(oNameQuery.toString()),null); Iterator i = oSet.iterator (); ObjectName perfOn = null;if (i.hasNext ()) {  perfOn=(ObjectName) i.next(); }

可以对以上的代码稍加修改,为 oNameQuery添加不同的特性和值就可以查询与该查询规则相匹配的其他 MBean ObjectName。例如,您可以将 Perf 替换为 Servlet , 这样您就会得到服务器中所有 servlet 的一组 ObjectName。

oNameQuery.append(",type=").append("Servlet");

我们也可以传递其他 MBean 类型来查找相关的 MBean。一些 MBean 类型(例如,Perf)会在应用服务器中提供单个的实例,但其他 MBean类型(例如,servlet 和 EJB)会在应用服务器中提供多个实例。在后面的情况中,MBean可以由它的名字进一步地识别。例如,可以在查询串中添加以下一行来查找名字准确为“myServletName”的 ObjectName。

oNameQuery.append("name=").append(myServletName);

请保留对本步骤中找到的 ObjectName 的引用,因为这些 ObjectName 以下步骤将会使用到。

步骤 3:设置装备级别


缺省情况下并没有设置 PMI 的装备级别。因此,必须将PMI 数据设置为适当的装备级别(通过程序、使用管理控制台或是使用管理脚本均可设置)。不管哪种方法,级别设置均可立即生效,无需重启服务器。

以下代码显示了如何通过 PerfMBean 在程序中设置 MBean 的装备级别:通过传递 MBean 的 ObjectName (从步骤 2中得到)、一个可选的 StatDescriptor(在本例中为空)以及期望的级别来构建它的一个 MBeanLevelSpec 对象,StatDescriptor是用于指定该 MBean 中的 PMI 数据的一个子集,在步骤 5 中将会对它进行描述。请注意可以使用多个 ObjectName 来创建一批MBeanLevelSpec,它们可以同时传递来设置多个 MBean 的装备级别。

 // First,set the parameter and signature arrays Object[] params = new Object[2]; params[0] = new MBeanLevelSpec(mbeanObjectName,null,PmiConstants.LEVEL_HIGH);  params[1] = new Boolean(true);  String[] signature= new String[]{"com.ibm.websphere.pmi.stat.MBeanLevelSpec","java.lang.Boolean"};  ac.invoke(perfOn,"setInstrumentationLevel",params,signature);

步骤 4: 从单个 MBean 获取 PMI 数据


如果一个单个的 MBean 提供了 Stats 属性,那么一旦在步骤 2 中得到了 ObjectName,就可以通过从 MBean中获取 Stats 属性来得到相关的 PMI 数据。再一次注意,通过各个 MBean 并不能设置装备级别。

Stats aStats = (Stats)ac.getAttribute(mbeanObjectName,"Stats");

步骤 5:从 PerfMBean 获取 PMI 数据


在步骤 4 中,一次 getAttribute 调用只能从某一 MBean 得到一个 Stats 对象。要从多个 MBean 得到 Stats对象,您需要多次调用 getAttribute。由于 getAttribute 是一个远程 JMX 调用,多次调用会带来很大的通信开销。PerfMBean被设计为可以以一种更为有效和灵活的方式来进行数据访问。PerfMBean 提供了以下的数据访问方法:

使用 PerfMBean 从单个 MBean 获取性能数据

以下的代码返回 MBean 中的 Stats 对象。由于在这里只传递一个 MBean,所以它等价于直接从 MBean获取 Stats 属性。

Object[] params = new Object[]{myObjectName,new Boolean(false)};  // set true to return data in the submodulesstring[] signature= new String[]{"javax.management.ObjectName","java.lang.Boolean"}; Stats myStats =  (Stats)ac.invoke(perfOn,"getStatsObject",params,signature);

在上面的代码中,将 PMI 的 Boolean 参数设置为 true 就可返回那个 MBean 及其子模块中的所有 PMI 数据。例如,如果您为某一 Web 应用程序查询数据并将 Boolean 参数设置为 true ,那么 PMI 数据就会返回给该 Web 应用程序以及它下面的所有 servlet。在其他 API 中也可以将 Boolean 参数设置为 true 来获取 PMI 数据。

使用 PerfMBean 从多个 MBean 获取性能数据

以下代码返回多个 MBean 的 Stats对象。这往往比单独获取数据来得有效。

ObjectName[] myOnArray;  // myOnArray is the array of all the Mbeans you want to get PMI dataObject[] params = new Object[]{myOnArray,new Boolean(false)};  // set true to return data recursivelyString[] signature= new String[]{"[Ljavax.management.ObjectName;","java.lang.Boolean"};Stats[] myStatsArray = (Stats[])ac.invoke(perfOn,"getStatsArray",params,signature);

从没有 MBean 的 PMI 模块/子模块获取性能数据

调用 getStatsObject 方法可以访问在服务器中没有匹配的MBean 的 PMI 模块和子模块。例如,PMI 模块“threadPoolModule”是一个逻辑组,它包含所有线程池聚集的 PMI数据。然而,并没有用于这一逻辑组运行时 MBean。在本例中,对于 PMI 模块/子模块,我们构建了一个 MBeanStatDescriptor,它包含了一个 MBean ObjectName和一个 StatDescriptor。其中 ObjectName 标识一个 MBean,而 StatDescriptor 指明 PMI 树中的 MBean的相关路径。MBeanStatDescriptor 比 MBean 提供更好的粒度的 PMI 访问。在步骤 3 中也使用 ObjectName 和 StatDescriptor来构建 MBeanLevelSpec。

以下的代码包含了 threadPoolModule 的 PMI 数据。服务器 ObjectName 表明它是从以该服务器为根的 PMI 数据开始的,并且 StatDescriptor 中的相关路径是来自该根的 threadPoolModule。

ObjectName serverON;  //  this is the ObjectName for the server you want to query PMI dataStatDescriptor mysd = new StatDescriptor(new String[]{PmiConstants.THREADPOOL_MODULE});MBeanStatDescriptor mymsd = new MBeanStatDescriptor(serverON,mysd);Object[] params = new Object[]{mymsd,new Boolean(false)};  String[] signature= new String[]{"com.ibm.websphere.pmi.stat.MBeanStatDescriptor",   "java.lang.Boolean"}; Stats myStats = (Stats)ac.invoke(perfOn,"getStatsObject",params,signature);

如果您知道 ObjectName 和 StatDescriptor,就可直接构造一个 MBeanStatDescriptor。否则您需要通过 PerfMBean中的 listStatMembers 方法来找出所有的 MBeanStatDescriptor。listStatMembers(ObjectName)和 listStatMembers(MBeanStatDescriptor)方法返回 PMI 树一级子节点的一组 MBeanStatDescriptor。因此,递归调用 listStatMembers方法就可以得到所有的 MBeanStatDescriptor,从而找到您期望得到的那一个。请注意 StatDescriptor 必须为空;这样的话 MBeanStatDescriptor 就提供了与它的 ObjectName 一样的 PMI 数据。

从多个 MBeanStatDescriptor 获取性能数据

这种方法通过一次 JMX 调用就可返回多个 MBeanStatDescriptor 的一批 Stats 对象,它通常比多次 JMX调用来得有效。以下的代码显示了如何使用这种方法:

MBeanStatDescriptor[] myMsdArray;  // myMsdArray is the array of MBeanStatDescriptors you want to get PMI dataObject[] params = new Object[]{myMsdArray,new Boolean(false)};  // set true to return data recursivelyString[] signature= new String[]{"[Lcom.ibm.websphere.pmi.stat.MBeanStatDescriptor;",  "java.lang.Boolean"}; Stats[] myStatsArray = (Stats[])ac.invoke(perfOn,"getStatsArray",params,signature);

在步骤 5 中,我们用不同的方式来调用 PerfMBean 中的 getStatsObject和 getStatsArray 以获取期望的 PMI 数据。使用 ObjectName 或者 MBeanStatDescriptor,您就可检索 PMI数据而不必考虑是否存在作为该数据的统计提供者的 MBean。在所有的 getStatsXXX 方法中,给 Boolean 参数传递 true 或 false 表明是否要为 PMI 提供整棵的子树。

步骤 6:检索静态配置信息


为了降低通信成本,在步骤 4 和 5 中检索PMI 数据时 PMI 并不返回静态配置信息(如数据名称和描述)。然而,您可以单独得到静态信息,并且在需要时将它与 PMI数据绑定。请使用以下的代码来从服务器获取所有的配置信息,查找某一 MBean 的 PmiModuleConfig,并将配置数据和 Stats数据绑定在一块。请将 PmiModuleConfigs 高速缓存,这样就不需要每次都启动远程调用了。

 // get all the configs in one call and cache it in your client program PmiModuleConfig[] configs = (PmiModuleConfig[])ac.invoke(perfOn,"getConfigs",null,null); PmiModuleConfig myConfig = PmiClient.findConfig(configs,myMBeanObjectName); myStats.setConfig(myConfig); // this is an API extended by PMI

步骤 7:从Stats 对象获取各种 PMI 计数器


步骤 4 和 5 当使用单个 MBean 或 PerfMBean 时返回了作为Stats 对象的 PMI。一个 Stats 对象包含一列实现不同数据类型(如表 1 所示)的 PMI 数据。Stats对象在以递归模式查询数据时也可以选择性地包括 Stats 对象列表。以下样本代码显示如何从 Stats 对象获取各种 PMI 计数器。请注意 WebSphereApplication Server V5将 J2EE 性能数据框架的接口打包在 com.ibm.websphere.management.statistics 中。以下的代码使用这个包中的接口。在样本 下载代码中,我们使用 com.ibm.websphere.pmi.stat 包中的 WebSphere 扩展接口来提供其他方法,如获取 sub-stat。

// get all the data from the Stats object        Statistic[] dataMembers = stat.getStatistics();if (dataMembers != null)  { for (int i=0; i<dataMembers.length; i++) { // For each data,cast it to be the real Statistic type  // so that we can get the value from each Statistic. // Can call the following common methods without knowing the data type: // getName(),getDescription(),getStartTime(),getLastSampleTime()                    // check the data type and cast the data to the right type if (dataMembers[i] instanceof CountStatistic) {  // cast it to CountStatistic and call the API to get the data value } else if (dataMembers[i] instanceof TimeStatistic) {  // cast it to TimeStatistic and call the API to get the data value } else if (dataMembers[i] instanceof RangeStatistic) {  // cast it to RangeStatistic and call the API to get the data value }   }}

结束语


本文介绍了 PMI、JMX MBean 和 J2EE性能数据框架之间的关系。PMI 实现了 J2EE 性能数据框架并允许通过 JMX 接口进行数据访问。PerfMBean 通过程序为每个 PMI模块设置装备级别。一旦 PMI 数据可用,这种数据就可通过各种 MBean 或 PerfMBean 获取。使用 MBeanStatDescriptor来从在服务器中没有映射的 MBean 的 PMI 模块/子模块获取 PMI 数据。从多个 MBean 获取 PMI 数据的一种更有效的方法是使用 PerfMBean来产生单个 JMX 调用,而不是为各个 MBean 产生多个 JMX 调用。检索静态配置信息及导航 Stats 对象的 API 也同样可用。

PMI 数据有助于实现性能监控和调优。例如,WebSphere Application Server V5.02 附带的性能顾问监控 PMI数据并通过调整应用服务器配置给出性能优化的建议。基于每台服务器中的性能数据,使用 PMI 的监控工具有助于进行工作负载管理、容量规划并通过检测相关PMI 计数器的值来生成警告。

0 0
原创粉丝点击