首页 > 其他分享 >arthas命令实现原理-MBean的使用

arthas命令实现原理-MBean的使用

时间:2024-01-11 15:37:45浏览次数:25  
标签:group addItem MXBean MBean arthas 原理 jvmModel public

MBean,MXBean简介
MBean是一个托管的java bean对象,MBean是一个托管Java对象,类似于JavaBeans组件,遵循JMX(Java Management Extensions,即Java管理扩展)规范中规定的设计模式。MBean可以表示任何需要管理的资源。MBeans 公开了一个管理接口,该接口由以下部分组成:

一组可读或可写属性,或两者兼而有之
一组可调用的操作
自我描述
JMX 规范中定义了如下五种类型的MBean:

Standard MBeans
Dynamic MBeans
Open MBeans
Model MBeans
MXBean
本文主要描述standard MBeans以及MXBeans类。

Stadard Mbeans
标准的MBean就是定义一个java 接口,该接口必须以MBean结尾,同时定义定义一个接口的实现类,实现类的名称是接口名称去掉MBean后的名字。 每一个定义在接口中的方法代表一个MBean的属性或者操作。MBean通过公共方法以及遵从特定的设计模式封装了属性和操作,以便暴露给管理应用程序。例如,一个只读属性在管理构件中只有Get方法,既有Get又有Set方法表示是一个可读写的属性。

定义HelloMBean接口,该接口必须以MBean结尾

package com.allen.mbean;
public interface HelloMBean {
public void sayHello();
public int add(int x, int y);
public String getName();
public int getCacheSize();
public void setCacheSize(int size);
}
定义MBean接口的实现类,当前类的名称为接口名称去掉结尾的MBean剩余的字符

package com.allen.mbean;
public class Hello implements HelloMBean {
public void sayHello() {
System.out.println("hello, world");
}
public int add(int x, int y) {
return x + y;
}
public String getName() {
return this.name;
}
public int getCacheSize() {
return this.cacheSize;
}
public synchronized void setCacheSize(int size) {
this.cacheSize = size;
System.out.println("Cache size now " + this.cacheSize);
}
private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int
DEFAULT_CACHE_SIZE = 200;
}

创建测试MBean功能的类, 当前类启动后在MBeanServer中注册Hello这个对象。 启动参数中增加 -Djava.rmi.server.hostname=localhost 当时我的mac电脑启动程序每添加这个参数导致jconsole连不上。

package com.allen.mbean;
import javax.management.*;
import java.lang.management.ManagementFactory;
public class HelloMBeanTest {
public static void main(String[] args) throws InterruptedException, MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=Hello");
Hello mbean = new Hello();
mbs.registerMBean(mbean, name);
Thread.sleep(Long.MAX_VALUE);
}
}
使用jconsole连到当前jvm进程在MBean的tab页下可以看到有CacheSize,Name属性, sayHello,add操作

 

其实还可以通过jmx 连接到当前jvm,使用jmx远程操作当前Mbean,代码如下,其中FindUrlByPid 是本地通过pid查找到对应进程jmx的url串, 可通过获取对应的源码

package com.allen.mbean;
import javax.management.*;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
public class ClientDemo {
// 执行参数中注意增加上HelloMBeanTest运行的pid
public static void main(String[] args) throws IOException, MalformedObjectNameException, InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException {
String url = FindUrlByPid.main(args);
if (url == null) {
System.out.println("can not find the jmx url by pid");
return;
}
JMXServiceURL jmxServiceURL = new JMXServiceURL(url);
JMXConnector connect = JMXConnectorFactory.connect(jmxServiceURL, null);
MBeanServerConnection mBeanServerConnection = connect.getMBeanServerConnection();
ObjectInstance objectInstance = mBeanServerConnection.getObjectInstance(new ObjectName("com.example:type=Hello"));
System.out.println(mBeanServerConnection.getAttribute(new ObjectName("com.example:type=Hello"), "Name"));
mBeanServerConnection.invoke(new ObjectName("com.example:type=Hello"), "sayHello", new Object[]{}, new String[]{});
}
}

MXBeans
MXBean是一种特殊的MBean,不仅特殊在名字不一样,主要是在于在接口中会引用到一些其他类型的类时,其表现方式的不一样。在MXBean中,如果一个MXBean的接口定义了一个属性是一个自定义类型,如果MXBean定义了一种自定义的类型,当JMX使用这个MXBean时,这个自定义类型就会被转换成一种标准的类型,这些类型被称为开放类型,是定义在javax.management.openmbean包中的。而这个转换的规则是,如果是原生类型,如int或者是String,则不会有变化,但如果是其他自定义类型,则被转换成CompositeDataSupport类,这样,JMX调用这个MXBean提供的接口的时候,classpath下没有这个自定义类型也是可以调用成功的,但是换做MBean,则调用方的classpath下必须存在这个自定义类型的类定义。

在标准Mbean的基础上增加了User类型的属性,jconsole查看属性时会显示不可用

 

将MBean更换为MXBean后,通过jconsole查看属性时可以正常查看到

 

arthas使用的MXBean
arthas中部分系统状态信息的命令的实现是通过MXBean的调用返回对应的数据,下表是我现阶段的统计的命令的以及当前命令使用到的MXBean

命令

MXBean

描述

vmoption

HotSpotDiagnosticMXBean

通过该命令可以查看或者修改jvm 诊断性配置参数,如 PrintGC, PrintGCDetails等参数

thread

ThreadMXBean

通过该命令我们可以查看线程线程信息

jvm

RuntimeMXBean

ClassLoadingMXBean

CompilationMXBean

GarbageCollectorMXBean

MemoryManagerMXBean

MemoryMXBean

OperatingSystemMXBean

当前命令会展示jvm的runtime, CLASS-LOADING,COMPILATION等一系列状态信息

dashboard

聚合几种mxbean进行信息的获取

仪表盘的作用主要是展示thread, memory, gc, vm信息,也是通过jvm命令中的个别MXBean实现的

arthas-jvm命令实现流程
从前面章节可以看出arthas服务端时怎么处理请求, 当我们在客户端执行jvm命令之后,到arthas内部后由JvmCommand类进行处理,核心方法为:

@Override
public void process(CommandProcess process) {
JvmModel jvmModel = new JvmModel();
addRuntimeInfo(jvmModel);
addClassLoading(jvmModel);
addCompilation(jvmModel);
if (!garbageCollectorMXBeans.isEmpty()) {
addGarbageCollectors(jvmModel);
}
if (!memoryManagerMXBeans.isEmpty()) {
addMemoryManagers(jvmModel);
}
addMemory(jvmModel);
addOperatingSystem(jvmModel);
addThread(jvmModel);
addFileDescriptor(jvmModel);
process.appendResult(jvmModel);
process.end();
}

从上面的代码中,我们可以看出,当前方法核心流程就时创建一个JvmModel对象,向该对象中添加各类信息,运行信息,类加载信息,gc信息,内存占用,线程等各类信息,接下来我们就几种信息获取进行具体的分析。着重介绍Runtime信息,Classloading信息,Thread信息的获取,其它方面的信息与这三种实现方式大体一致。

Runtime信息
//RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
String bootClassPath = "";
try {
bootClassPath = runtimeMXBean.getBootClassPath();
} catch (Exception e) {
// under jdk9 will throw UnsupportedOperationException, ignore
}
String group = "RUNTIME";
jvmModel.addItem(group,"MACHINE-NAME", runtimeMXBean.getName());
jvmModel.addItem(group, "JVM-START-TIME", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(runtimeMXBean.getStartTime())));
jvmModel.addItem(group, "MANAGEMENT-SPEC-VERSION", runtimeMXBean.getManagementSpecVersion());
jvmModel.addItem(group, "SPEC-NAME", runtimeMXBean.getSpecName());
jvmModel.addItem(group, "SPEC-VENDOR", runtimeMXBean.getSpecVendor());
jvmModel.addItem(group, "SPEC-VERSION", runtimeMXBean.getSpecVersion());
jvmModel.addItem(group, "VM-NAME", runtimeMXBean.getVmName());
jvmModel.addItem(group, "VM-VENDOR", runtimeMXBean.getVmVendor());
jvmModel.addItem(group, "VM-VERSION", runtimeMXBean.getVmVersion());
jvmModel.addItem(group, "INPUT-ARGUMENTS", runtimeMXBean.getInputArguments());
jvmModel.addItem(group, "CLASS-PATH", runtimeMXBean.getClassPath());
jvmModel.addItem(group, "BOOT-CLASS-PATH", bootClassPath);
jvmModel.addItem(group, "LIBRARY-PATH", runtimeMXBean.getLibraryPath());

从上面的代码中,可以清晰的看出来Runtime信息都是通过RuntimeMXBean对象获取的,通过该对象我们可以获取系统运行时的一些信息。通过这个MXBean我们可以获取到很多有用的信息:

通过getName信息,可以获取到当前进程的id, getName获取的数据的格式时pid@hostname
通过getStartTime,可以获取到jvm启动的时间
通过getInputArguments,可以获取到jvm启动时间
。。。 不一一举例
Classloading信息
ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
private void addClassLoading(JvmModel jvmModel) {
String group = "CLASS-LOADING";
jvmModel.addItem(group, "LOADED-CLASS-COUNT", classLoadingMXBean.getLoadedClassCount());
jvmModel.addItem(group, "TOTAL-LOADED-CLASS-COUNT", classLoadingMXBean.getTotalLoadedClassCount());
jvmModel.addItem(group, "UNLOADED-CLASS-COUNT", classLoadingMXBean.getUnloadedClassCount());
jvmModel.addItem(group, "IS-VERBOSE", classLoadingMXBean.isVerbose());
}
通过ClassLoadingMXBean可以获取到jvm加载到类个数,卸载到类个数,总共加载到类个数,是否为类加载系统启用verbose输出,其实该MXBean还有一个setVerbose方法,用于动态设置类加载的verbose属性

Thread信息
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
private void addThread(JvmModel jvmModel) {
String group = "THREAD";
jvmModel.addItem(group, "COUNT", threadMXBean.getThreadCount())
.addItem(group, "DAEMON-COUNT", threadMXBean.getDaemonThreadCount())
.addItem(group, "PEAK-COUNT", threadMXBean.getPeakThreadCount())
.addItem(group, "STARTED-COUNT", threadMXBean.getTotalStartedThreadCount())
.addItem(group, "DEADLOCK-COUNT",getDeadlockedThreadsCount(threadMXBean));
}
核心是通过ThreadMXBean进行数据的获取, 在arthas,jvm命令中使用ThreadMXBean相对简单,仅仅获取的线程数,守护线程数,peak状态的线程数,启动过的线程数,死锁线程数。

dashboard命令同样会展示cpu占用率比较高的10个线程, 其中还使用到了getThreadCpuTime的方法,通过该方法可以获取的线程的的cpu时间

arthas用到这些MXBean的作用
java APM(Application Performance Monitor 应用性能监控)程序,中对与jvm的信息采集中,使用到很多MXBean,如我之前研究的的pinpoint实现中,对于应用性能采集:

activethread, buffer, cpu, deadlock, filedscriptor, gc, loadedclass, memory, totalthread这些指标跟arthas的实现获取方式几乎一致,都是通过mxbean获取的。

 

后续如果有项目需求,采集系统性能,个人觉得完全可以通过这样的jdk提供的MXBean进行获取
————————————————
版权声明:本文为CSDN博主「丁Allen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lian_forever/article/details/118858587

标签:group,addItem,MXBean,MBean,arthas,原理,jvmModel,public
From: https://www.cnblogs.com/xd502djj/p/17958660

相关文章

  • 可信时间戳如何生成?可信时间戳技术原理
    可信时间戳已成为确立电子数据法律效力的重要技术之一。在全球信息化的大趋势下,以计算机及其网络为依托的电子数据,在证明案件事实的过程中起着越来越重要的作用。电子数据具有脆弱性、易变性、隐蔽性、载体多样性等特点,容易被复制、删除、篡改且难以被发现。因此,电子数据在实际的司......
  • 记使用Arthas定位并解决Java应用死锁问题
    背景在一次生产环境部署后,我们的JavaWeb应用开始表现出严重的性能下降。用户报告说网页响应变得非常慢,有时甚至完全无响应。初步检查服务器资源和应用日志未发现明显的问题,我们怀疑可能是应用内部出现了死锁。引入Arthas为了不影响生产环境运行,我们决定使用Arthas进行问题诊断。Ar......
  • 01 Docker 安装:入门案例带你了解容器技术原理
    Docker能做什么?众所周知,Docker是一个用于开发,发布和运行应用程序的开放平台。通俗地讲,Docker类似于集装箱。在一艘大船上,各种货物要想被整齐摆放并且相互不受到影响,我们就需要把各种货物进行集装箱标准化。有了集装箱,我们就不需要专门运输水果或者化学用品的船了。我们可以把......
  • 25-稳定基石:带你剖析容器运行时以及 CRI 原理.md
    当一个Pod在Kube-APIServer中被创建出来以后,会被调度器调度,然后确定一个合适的节点,最终被这个节点上的Kubelet拉起,以容器状态运行。那么Kubelet是如何跟容器打交道的呢,它是如何进行创建容器、获取容器状态等操作的呢?今天我们就来了解一下。容器运行时(ContainerRuntim......
  • 06-无状态应用:剖析 Kubernete 业务副本及水平扩展底层原理
    在上两节课中,我们已经了解了Kubernetes中最关键的对象Pod,也学习了一些Pod的常见用法。每一个Pod都是应用的一个实例,但是通常来说你不会直接在Kubernetes中创建和运行单个Pod。因为Pod的生命周期是短暂的,即“用后即焚”。理解这一点很重要,这也是“不可变基础设施”这......
  • JVS逻辑引擎调用规则引擎:深入剖析工作原理与应用场景
    在当今的数字化时代,业务逻辑和规则的复杂性不断增加,这使得逻辑引擎和规则引擎在处理业务需求时显得尤为重要。逻辑引擎和规则引擎通过定义、解析和管理业务逻辑和规则,能够帮助企业提高工作效率、降低运营成本,并增强决策的科学性和准确性。本文将详细解释JVS逻辑引擎调用规则引擎的......
  • 电话光端机在通信网络中的作用与原理
    电话光端机在现代通信网络中扮演着至关重要的角色。本文旨在深入探讨电话光端机的工作原理及其在通信网络中的作用,并将文章中的关键词进行加粗处理,以便于理解。电话光端机的基本原理电话光端机主要由光发射器和光接收器两部分组成。光发射器的作用是将电信号转换为光信号,而光接收器......
  • MyBatis实战指南(二):工作原理与基础使用详解
    MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。那么,它是如何工作的呢?又如何进行基础的使用呢?本文将带你了解MyBatis的工作原理及基础使用。一、MyBatis的工作原理1.1MyBatis的工作原理工作原理图示:1、读取MyBatis配置文件mybatis-config.xml为MyBat......
  • 相机标定原理
    相机标定后可以得到什么?相机的内参矩阵A(dx,dy,r,u,v,f),外参矩阵[R|T]、畸变系数[k1,k2,k3,~,p1,p2,~]。•内参矩阵各元素意义:一个像素的物理尺寸dx和dy,焦距f,图像物理坐标的扭曲因子r,图像原点相对于光心成像点的的纵横偏移量u和v(像素为单位)。•外参矩阵:世界坐标系转换到相机坐标系......
  • MyBatis实战指南(二):工作原理与基础使用详解
    MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。那么,它是如何工作的呢?又如何进行基础的使用呢?本文将带你了解MyBatis的工作原理及基础使用。一、MyBatis的工作原理1.1MyBatis的工作原理工作原理图示:1、读取MyBatis配置文件mybatis-config.xml为MyBa......