JMX
JMX的全稱為Java Management Extensions. 顧名思義,是管理Java的一種擴展。這種機制可以方便的管理、監控正在運行中的Java程序。常用於管理線程,內存,日志Level,服務重啟,系統環境等
基本術語
-
MBean:
是Managed Bean的簡稱,可以翻譯為“管理構件”。在JMX中MBean代表一個被管理的資源實例,通過MBean中暴露的方法和屬性,外界可以獲取被管理的資源的狀態和操縱MBean的行為。事實上,MBean就是一個Java Object,同JavaBean模型一樣,外界使用自醒和反射來獲取Object的值和調用Object的方法,只是MBean更為復雜和高級一些。MBean通過公共方法以及遵從特定的設計模式封裝了屬性和操作,以便暴露給管理應用程序。例如,一個只讀屬性在管理構件中只有Get方法,既有Get又有Set方法表示是一個可讀寫的屬性。一共有四種類型的MBean:- Standard MBean,
- Dynamic MBean,
- Open MBean,
- Model MBean。
-
MBeanServer:
MBean生存在一個MBeanServer中。MBeanServer管理這些MBean,並且代理外界對它們的訪問。並且MBeanServer提供了一種注冊機制,是的外界可以通過名字來得到相應的MBean實例。 -
JMX Agent:
Agent只是一個Java進程,它包括這個MBeanServer和一系列附加的- - - MbeanService。當然這些Service也是通過MBean的形式來發布。 -
Protocol Adapters and Connectors:
MBeanServer依賴於Protocol Adapters和Connectors來和運行該代理的Java虛擬機之外的管理應用程序進行通信。Protocol Adapters通過特定的協議提供了一張注冊在MBeanServer的MBean的視圖。例如,一個HTML Adapter可以將所有注冊過的MBean顯示在Web 頁面上。不同的協議,提供不同的視圖。Connectors還必須提供管理應用一方的接口以使代理和管理應用程序進行通信,即針對不同的協議,Connectors必須提供同樣的遠程接口來封裝通信過程。當遠程應用程序使用這個接口時,就可以通過網絡透明的和代理進行交互,而忽略協議本身。Adapters和Connectors使MBean服務器與管理應用程序能進行通信。因此,一個代理要被管理,它必須提供至少一個Protocol Adapter或者Connector。面臨多種管理應用時,代理可以包含各種不同的Protocol Adapters和Connectors。當前已經實現和將要實現的Protocol Adapters和Connectors包括: RMI Connector, SNMP Adapter, IIOP Adapter, HTML Adapter, HTTP Connector.
Adapter 和Connector的區別在於:Adapter是使用某種Internet協議來與JMX Agent獲得聯系,Agent端會有一個對象 (Adapter)來處理有關協議的細節。比如SNMP Adapter和HTTP Adapter。而Connector則是使用類似RPC的方式來訪問Agent,在Agent端和客戶端都必須有這樣一個對象來處理相應的請求與應答。比如RMI Connector。
Spring JMX
為了將一個POJO變為MBean,一個做法是定義一個XXXXMBean為名的接口,然后實現它。
而Spring提供了一種更簡單的方法,Annotation注釋即可,既可以將POJO變為MBean,還可以為屬性,方法及其參數都加上描述,為JConsole進行操作時提供更好的幫助信息。
@ManagedResource
在類上使用,把類標記為MBean。@ManagedOperation
在可操作的方法加使用。@ManagedAttribute
在字段上使用。如果屬性是可讀可寫的,就在getter和setter上都注釋,只讀的話就只在getter上注釋。
package com.example.demo.jmx;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicLong;
@Component
@ManagedResource(objectName="test.jmx:name=ServerManager",
description="Server manager.")
public class Hello {
private final AtomicLong alarm = new AtomicLong(0);
@ManagedAttribute
public Integer getAlarm() {
return alarm.intValue();
}
@ManagedOperation
public void setAlarm() {
alarm.incrementAndGet();
}
}
新建一個SpringBoot項目,添加像上面使用注解的類,啟動項目后,就可以在JConsole查看MBean的情況了。
支持JMX遠程連接
如果是用Jolokia將JMX Restful JSON的話,遠程連接就不是必須的。如果仍然要遠程連接,可以在啟動JVM時加上系統參數
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=3099
JConsole
如果JConsole與應用在同一台機器,直接選擇該進程
遠程進程URL可以簡單的寫host:port
如 localhost:2099
,
練打字的話寫完整版的service:jmx:rmi:///jndi/rmi://localhost:2099/jmxrmi
自定義MBean(非Spring方式)
- 新建接口
package com.example.demo.jmx;
public interface AlarmMBean {
Integer getAlarm();
void setAlarm();
}
- 新建實現類
package com.example.demo.jmx;
import java.util.concurrent.atomic.AtomicLong;
public class Alarm implements AlarmMBean{
private final AtomicLong alarm = new AtomicLong(0);
@Override
public Integer getAlarm() {
return alarm.intValue();
}
@Override
public void setAlarm() {
alarm.incrementAndGet();
}
}
- 注冊MBean
Demo程序在main
訪法中調用即可
private static void registerMBean(String module,Integer errorCode) {
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("jmxBean:name="+module+"-"+errorCode);
//create mbean and register mbean
server.registerMBean(new Alarm(), name);
} catch (Exception e) {
System.out.println(e);
}
}
- 支持JConsole遠程連接
private static void jmxConnect() {
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
LocateRegistry.createRegistry(9999);
//URL路徑的結尾可以隨意指定,但如果需要用Jconsole來進行連接,則必須使用jmxrmi
JMXServiceURL url = new JMXServiceURL
("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi");
JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
System.out.println("begin rmi start");
jcs.start();
System.out.println("rmi start");
} catch (Exception e) {
System.out.println(e);
}
}
這樣就可以在JConsole中用localhost:9999連接。
prometheus jmx_exporter
通過HTTP公開JMX Bean以供Prometheus使用的過程
https://github.com/prometheus/jmx_exporter
配置文件config.yaml
---
lowercaseOutputLabelNames: true
lowercaseOutputName: true
#whitelistObjectNames: ["java.lang:type=OperatingSystem","jmxBean:type=custom",*]
#blacklistObjectNames: []
rules:
#在JConsole中可觀察到自定義MBean:jmxBean:name=reactor-100102
- pattern: 'jmxBean<name=(\w+)-(\d+)><>(alarm):'
name: test_$1_$2
labels:
"module": "$1"
"errorCode": "$2"
type: COUNTER
attrNameSnakeCase: true
whitelistObjectNames 中配置MBean的白名單,缺省設置默認是全部公開的MBean。
()
每個小括號的正則結果對應$1,$2...的變量。
更多的選項設置Github文檔中有更詳細描述和示例配置。
模式匹配格式 (pattern)
與模式匹配的輸入格式為
domain<beanpropertyName1=beanPropertyValue1, beanpropertyName2=beanPropertyValue2, ...><key1, key2, ...>attrName: value
部分 | 描述 |
---|---|
domain | 定義ObjectName時,JMX對象名稱中冒號之前的部分。 |
beanProperyName/Value | Bean屬性。這些是JMX對象名稱中冒號后面的鍵/值。 |
key | 如果遇到復合數據或表格數據,則將屬性名稱添加到此列表中。 |
attrName | 屬性的名稱。對於表格數據,這將是列的名稱 |
value | 屬性的值。 |
預設格式
在大多數情況下,缺省格式將以一種可以產生健全度量標准的方式轉換bean。它是
domain_beanPropertyValue1_key1_key2_...keyN_attrName{beanpropertyName2="beanPropertyValue2", ...}: value
javaagent運行
要作為javaagent運行,請下載jar並運行:
java -javaagent:./jmx_prometheus_javaagent-0.12.0.jar=8081:config.yaml -jar yourJar.jar
現在可以在http://localhost:8081 上訪問指標
要將Java代理綁定到特定IP,請將端口號更改為host:port。
JavaAgent.java
Prometheus和Grafana的配置這里不講,可以找其它文章進行配置。
參考鏈接:
https://www.cnblogs.com/dongguacai/p/5900507.html
https://blog.csdn.net/u013256816/article/details/52800742
https://github.com/springside/springside4/wiki/Jmx
https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-jmx.html
https://github.com/prometheus/jmx_exporter