最近在看flume的监控源码,发现flume的监控metrics是存放在MBean中,再由web服务暴露到其他监控系统中。这次又get到了一个新知识点,今天给大家分享一下。
什么是JMX和MBean?
JMX(Java管理扩展)提供了一种简单的、基础的方法,用来管理诸如应用、设备和服务等资源。由于JMX技术是动态的,你可以使用JMX技术来监控和管理处于创建、安装和运行态的资源。你甚至可以使用JMX技术监控和管理Java虚拟机。我们通过一些监控程序获取到当前JVM的一些状态值,就是通过mbean暴露。下面的内存统计可以查看实时的堆内存使用量。
MBean是一个被管理的Java对象,它遵从JMX规范。MBean可以表示设备、应用或者任何需要被管理的资源。
MBeans暴露如下管理接口:
- 一组可读或者可写属性,通过可写属性可以从外部操作JVM里面的行为,例如执行GC。
- 一组调用方法。
- 自我描述。
例如下面的mbean,可以操作JVM 的GC
如何使用MBean
下面通过一个实例,介绍怎么向JMX注册MBean。
按照约定,MBean接口的名称由其实现类名+MBean后缀组成。根据JMX规范,MBean接口由属性(可读getter方法或者可写setter方法)和操作(暴露的方法)组成。
下面代码将定义一个channel的指标MBean,获取启动时间、结束时间、连接数
public interface ChannelMetricsMBean {
long getStartTime();
long getStopTime();
long getConnectionCount();
}
public class ChannelMetrics implements ChannelMetricsMBean {
private AtomicLong counter = new AtomicLong(0);
private long startTime = 0;
private long stopTime = 0;
public void start() {
// to do init
startTime = System.currentTimeMillis();
}
public void stop() {
stopTime = System.currentTimeMillis();
}
public void addConnectionCount() {
counter.incrementAndGet();
}
@Override
public long getStartTime() {
return startTime;
}
@Override
public long getStopTime() {
return stopTime;
}
@Override
public long getConnectionCount() {
return counter.get();
}
}
将mbean注册到 JMX
public class MBeanMain {
public static void main(String[] args) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
// 注册被管理的对象
ObjectName objectName = new ObjectName("test.mbean.channel:type=test1");
ChannelMetrics channelMetrics = new ChannelMetrics();
mBeanServer.registerMBean(channelMetrics, objectName);
runMonitor(channelMetrics);
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void runMonitor(ChannelMetrics channelMetrics) {
channelMetrics.start();
//每10秒添加一个连接
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("add one connection");
channelMetrics.addConnectionCount();
}
}, 1, 10, TimeUnit.SECONDS);
}
}
我们可以通过jconsole看下效果