JMX的简单回顾

本文通过实例介绍如何利用Java Management Extensions (JMX)进行远程监控。包括MBean接口定义、资源变化通知机制、MBean服务器配置及客户端调用流程。

之前有了解过JMX,工作中有时候也在用,但是啥东西不系统的学一下,你的内心是空虚的,因此这两天整了整。就放些代码吧,和JMX规范的架构图把。

 

JMX 架构图:

JMX架构图

 

 

package com.blackbeans.example.mbeans;

/**
 * Mbean接口
 * @author blackbeans
 *
 */
public interface GunMBean {
	
	public void aimAndShoot(String[] targetName);
}

 

 

package com.blackbeans.example.mbeans;
import javax.management.AttributeChangeNotification;
import javax.management.NotificationBroadcasterSupport;

/**
 * 实现的Mbean,即所谓的JMX Resources
 * 
 * @author blackbeans
 * 
 */
public class Gun extends NotificationBroadcasterSupport implements GunMBean {

	private String gunModel;

	public Gun(String gunModel) {
		this.gunModel = gunModel;
	}

	@Override
	public void aimAndShoot(String[] targetNames){
		
		for(String targetName : targetNames ){
		System.out.println(gunModel + "aim at "+ targetName +" !");
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println(gunModel + " fire !");
		}
		
		AttributeChangeNotification notification = new AttributeChangeNotification(this, 0, 0L, "Gun shot!", null, null, null, null);

		sendNotification(notification);
		
	}
}

   为了监控MBean的值变,JMX 的Agent Level有提供基于java 事件的Notification机制可以通知其他的JMX当前的资源发生了变更。JMX 的Agent Level提供了Monitor服务并通知所有的Listener。

 

 

package com.blackbeans.example.mbeans;

import javax.management.Notification;
import javax.management.NotificationListener;

public class GunFiredNotificationListener implements NotificationListener {

	@Override
	public void handleNotification(Notification notification, Object handback) {
		System.out.println("notifyInfo:\t"+notification+"\n handback:\t"+handback);

	}

}

 

   MBServer

 

package com.blackbeans.example.mbeans;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class MyMBeanServer {
	
	private MBeanServer mbServer;
	
	public MyMBeanServer()
	{
		this.mbServer = ManagementFactory.getPlatformMBeanServer();
		try {
			Registry reg = LocateRegistry.createRegistry(9999);
			for(String bind : reg.list()){
				System.out.println(bind);
			}
			JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://192.168.1.101:9999/MBServer");
			JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbServer);
			connector.start();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	
	public void registerMBean(String objectName,Object obj)
	{
		ObjectName objName = null;
		try {
			objName = new ObjectName(objectName);
			this.mbServer.registerMBean(obj, objName);
			this.mbServer.addNotificationListener(objName, new GunFiredNotificationListener(), null, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public static void main(String[] args) throws InterruptedException {
		Gun gun = new Gun("AK-47");
		MyMBeanServer myServer = new MyMBeanServer();
		myServer.registerMBean(gun.getClass().getPackage().getName() + ":name="+gun.getClass().getSimpleName(), gun);
		Thread.sleep(100000);
	}
}

   MBeanClient

 

package com.blackbeans.example.mbeans;
import java.io.IOException;
import java.net.MalformedURLException;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;


public class MyMBeanClient{
	
	
	private MBeanServerConnection connection;
	public MyMBeanClient(String jmxUrl)
	{
		JMXServiceURL url = null;
		try {
			url = new JMXServiceURL(jmxUrl);
			JMXConnector connector = JMXConnectorFactory.connect(url);
			connector.connect();
			 this.connection = connector.getMBeanServerConnection();
			
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	public void invokeMethod(ObjectName objName,String opName ,Object[] paras,String[] signature)
	{
		
		
		try {
			this.connection.invoke(objName, opName, paras, signature);
			
		} catch (InstanceNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MBeanException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ReflectionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
			 
		String[] gunTypes = new String[]{"AK-47","M16"}; 
		
		MyMBeanClient client = new MyMBeanClient("service:jmx:rmi:///jndi/rmi://192.168.1.101:9999/MBServer");
		
		try {
			ObjectName objName = new ObjectName("com.blackbeans.example.mbeans:name=Gun");
			Object[] parameters = new Object[]{gunTypes};
			String[] signatures = new String[]{"[Ljava.lang.String;"};
			client.invokeMethod(objName, "aimAndShoot", parameters, signatures);
			
		} catch (MalformedObjectNameException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

 

   我的例子使用的JMX的RMI方式调用,当然你也可以选择使用本地方式或者使用Sun的 HtmlJmxAdapter 来完成JMX调用或者不用客户端直接使用jconsol连接上去调用即可.

 

reference:

                http://java.sun.com/developer/technicalArticles/J2SE/jmx.html

<think>好的,我需要帮助用户找到不使用PrometheusReporter的更简单的替代方案。用户之前已经得到了一些方法,比如JMX + Jolokia、自定义Reporter、日志+ELK等,但用户现在希望更简单的实现方式。 首先,回顾之前的回答,用户可能觉得之前的方案配置步骤较多,比如JMX需要配置端口、Jolokia代理,自定义Reporter需要编写代码,日志解析也需要ELK栈的搭建。用户现在想要更简单的,可能是指配置步骤少、依赖组件少的方法。 用户提到了站内引用,其中引用1提到PushGateway的稳定性问题,引用2涉及Flink SQL的平台化。不过用户指出这些引用仅供参考,重点还是上次的问题和回答。因此,我需要专注于之前提到的方案,并思考其中哪些可以简化。 可能的思路: 1. **日志输出+简单脚本分析**:如果用户不需要实时监控,可能直接使用Flink的日志输出RocksDB指标,然后用简单的grep或awk脚本定期提取关键指标,无需复杂的ELK栈。这可能更简单。 2. **利用Flink Web UI的内置指标**:虽然Web UI可能不直接显示RocksDB指标,但如果有办法通过REST API获取,可能结合脚本处理。但需要确认RocksDB指标是否通过Flink的REST API暴露。 3. **使用现有Metric Reporter中的其他内置Reporter**:比如SLF4JReporter直接将指标输出到日志,用户只需配置,无需额外组件,但需要处理日志解析。可能比JMX简单。 4. **Kubernetes原生监控工具**:比如使用kube-state-metrics或cAdvisor,但这些可能主要监控容器资源使用,而非应用层的RocksDB指标,可能不适用。 接下来,需要评估哪种方法最简单。比如,使用SLF4JReporter输出到日志,然后定期用脚本分析日志文件,可能不需要额外服务,只需配置Flink和写脚本。 验证可行性:查看Flink文档,确认是否可以通过SLF4JReporter输出RocksDB指标。配置步骤是否简单,是否只需几行配置,然后处理日志。 另外,用户提到希望更简单,可能不喜欢部署额外服务如InfluxDB、Prometheus、ELK等。因此,方案应尽量减少外部依赖。 可能的步骤: 1. 配置Flink使用SLF4JReporter,将指标输出到日志,间隔时间适当。 2. 编写脚本定期扫描日志,提取RocksDB相关指标,如block_cache_hit_rate等。 3. 脚本可以将数据保存到本地文件,或发送到简单的监控工具,如Netdata、Grafana本地实例等。 这种方法不需要额外的中间件,只需利用现有日志系统和简单脚本,可能符合用户“更简单”的需求。 还需要考虑如何过滤日志中的RocksDB指标,可能需要配置日志格式,使得指标容易解析,例如使用特定的格式输出,方便grep或awk提取。 总结:最简单的方案可能是使用SLF4JReporter输出指标到日志,配合简单脚本分析,无需额外服务,配置步骤最少。</think>根据您的需求,以下是不依赖 **PrometheusReporter** 且更轻量级的替代方案,按实现复杂度由低到高排序: --- ### 方案一:直接利用 Flink 日志输出(最快上手) #### 1. 配置 Flink 输出 RocksDB 指标到日志 在 Flink 配置文件中启用 `Slf4jReporter`,**仅需添加两行配置**: ```yaml # flink-conf.yaml metrics.reporter.log.class: org.apache.flink.metrics.slf4j.Slf4jReporter metrics.reporter.log.interval: 30 SECONDS # 按需调整间隔 ``` #### 2. 过滤关键指标 通过 `grep` 直接提取日志中的 RocksDB 指标: ```bash # 实时查看 Block Cache 命中率 kubectl logs -f <taskmanager-pod> | grep "rocksdb.block-cache-hit-rate" # 示例输出: # [rocksdb,block-cache-hit-rate] 0.923 ``` #### 3. 自动化采集(可选) 编写 Shell 脚本定时统计指标并生成报告: ```bash #!/bin/bash LOGFILE="/path/to/taskmanager.log" METRICS=("block-cache-hit-rate" "num-immutable-mem-table" "stall-percentage") for metric in "${METRICS[@]}"; do avg=$(grep "rocksdb.$metric" $LOGFILE | awk '{sum+=$NF} END {print sum/NR}') echo "Average $metric: $avg" done ``` --- ### 方案二:JMX 暴露 + JConsole 直连(无需中间件) #### 1. 启用 JMX Reporter 配置 Flink 直接开放 JMX 端口: ```yaml # FlinkDeployment 配置 spec: flinkConfiguration: metrics.reporter.jmx.class: org.apache.flink.metrics.jmx.JMXReporter metrics.reporter.jmx.port: 8789 ``` #### 2. 使用 JConsole 实时监控 本地通过端口转发连接 TaskManager: ```bash kubectl port-forward <taskmanager-pod> 8789:8789 ``` 打开 JConsole(JDK 自带工具),连接 `localhost:8789`,直接查看 `org.apache.flink.rocksdb` 下的指标[^1]。 --- ### 方案三:HTTP 端点 + Curl 查询(适合临时检查) 若已启用 **REST API 监控**(默认开启),通过 Flink Web UI 的端口获取 JSON 格式指标: ```bash # 获取 TaskManager 的指标列表 curl http://<taskmanager-ip>:8081/taskmanagers/<tm-id>/metrics | jq '.[] | select(.id | contains("rocksdb"))' # 示例输出: # { # "id": "rocksdb.block-cache-usage", # "value": "5242880" # } ``` --- ### 方案对比 | 方案 | 所需组件 | 实时性 | 运维复杂度 | |--------------------|-----------------|--------|------------| | **日志 + Grep** | 无 | 低 | ★☆☆☆☆ | | **JMX + JConsole** | JDK 工具链 | 高 | ★★☆☆☆ | | **REST API** | curl/jq | 中 | ★☆☆☆☆ | --- ### 选型建议 - **快速验证**:优先使用 **方案一**,5 分钟内可看到指标。 - **临时调试**:使用 **方案三** 直接通过 HTTP 接口拉取数据。 - **开发环境**:**方案二** 适合需要图形化界面观察趋势的场景。 --- ### 避坑指南 1. **日志量爆炸** 调整 Reporter 间隔至 1-5 分钟,并通过 `log4j.properties` 限制 RocksDB 指标日志级别: ```properties logger.metrics.name = org.apache.flink.metrics.slf4j logger.metrics.level = INFO ``` 2. **JMX 连接超时** 在 `JAVA_OPTS` 中添加 JMX 远程参数: ```yaml env: - name: JVM_ARGS value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false" ``` 3. **REST API 无数据** 确认 `metrics.reporters` 包含 `jmx` 或 `log`,否则指标不会上报到 REST 端点[^2]。 --- 以上方案均无需编码或部署额外服务,最低仅需 **修改配置文件+基础命令行工具** 即可实现监控。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值