1. 程式人生 > 程式設計 >老技術新談,Java應用監控利器JMX(1)

老技術新談,Java應用監控利器JMX(1)


先聊聊最近比較流行的梗,來一次靈魂八問。


配鑰匙師傅: 你配嗎?

食堂阿姨: 你要飯嗎?

算命先生: 你算什麼東西?

快遞小哥: 你是什麼東西?

上海垃圾分揀阿姨: 你是什麼垃圾?

滴滴司機: 你搞清楚自己的定位沒有?

理髮師傅:你照照鏡子看看你自己,覺得行嗎?

小區保安: 你是誰? 你從哪裡來?要到哪去?


順著這個梗,作為身經百戰的研發人員,我們繼續進行靈魂追問。


程式設計師:獲取應用的系統指標資訊,你能取嗎?

程式猿:動態修改應用的引數資訊,你能改嗎?

程式媛:遠端實現應用服務的重啟,你會啟嗎?


如果架不住靈魂拷問,那我們就潛心修煉一下,今天要分享的大豬蹄子(主角)—— JMX。


1.

啥是 JMX?


The Java Management Extensions (JMX) API is a standard API for management and monitoring of resources such as applications,devices,services,and the Java virtual machine. The JMX technology was developed through the Java Community Process (JCP) as Java Specification Request (JSR) 3,Java Management Extensions,and JSR 160,JMX Remote API.——摘自官網定義。


其實約莫能夠認識到,JMX 是 Java 管理擴充套件,主要用於管理和監視諸如應用程式、裝置、服務和 Java 虛擬機器器等資源的標準 API。JMX技術是通過 JCP 制定開發,由 JSR 3 和 JSR 160 規範定義而成。


稍微科普一下知識點。

JCP:是 Java Community Process 的縮寫,是一個主要由Java開發者以及被授權者組成的開放的國際組織,職能是開發和修訂 Java 技術規範。
JSR:是 Java Specification Requests 的縮寫,這個咱們之前已經談及過,再稍微再多說兩句。JSR 是指向 JCP 提出新增一個標準化技術規範的正式請求,是 Java 界的一個重要標準,任何人都可以提交 JSR ,以向 Java 平臺增添新的 API 和服務。
JSR 3:Java 管理擴充套件(JMX)規範。
JSR 160:Java 管理擴充套件(JMX)遠端API。
JSR N: 訪問 https://www.jcp.org/en/jsr/detail?id=N 直接修改傳入對應的 JSR 的編號 N,就可以查詢規範的更多細節。複製程式碼


2.

咋用類?


面對靈魂的拷問:獲取應用的系統指標資訊,你能取嗎


靈魂深處的回答:必須當然能取!接下來就告訴你怎麼取。


無論是程式初哥還是骨灰級戰神,大概率都會知道,獲取應用的系統指標資訊,無非就是監控資料直接落盤;被監控的應用提供介面噴指標資料等方式,來完成應用監控指標的輸出。


監控資料直接落盤的方式,可以細分為落到磁碟檔案、寫入共享儲存例如 redis。其中落入磁碟檔案,可以基於咱們之前談及的 flume 等開源的輪子完成資料採集;其中寫入 redis 的,監控管理應用,可以直接讀取指標資料使用就行。


被監控的應用提供介面噴指標資料的方式,無非就是被監控的應用,提供一個能噴監控資料的入口,司空見慣的實現,便是提供http 介面,然後再來一個監控管理的應用,再畫點頁面進行展示監控指標。


上面的實現方式,大體用一幅圖彙總如下。

其實上面這些實現方式都不是本次的重點,如果你稍微瞭解一下 JMX,則會驚喜的發現,上面的實現都相對比較繁瑣,因為 Java 中已經實現了大部分系統監控指標的獲取,並且提供 HTML 頁面來展示監控指標,非特殊情況下,其實無需再為監控管理應用,單獨再開發展示介面啦。


3.

程式碼走起。


感覺 JMX 是很豐滿,不知道現實是否會很骨感呢。也是時候擼點簡單的程式碼與 JMX 正式打個照面啦,JMX 應用的開發流程我簡單劃分為四步走。


第一步:按照 JMX 規範,定義一個 Java 介面,用來暴露可被訪問和操作的資訊。要注意:JMX的規範要求,介面的命名必須是實現類的名字後加 MBean。一口吃不了胖子,咱們還是從最簡單的程式碼開始擼起。

public interface AppMBean {
    public void welcome();
}複製程式碼

第二步:按照 JMX 規範,定義要被管理的 MBean,其實就是實現了上一步介面定義的一個普通的 Java 類。

public class App implements AppMBean {
    @Override
    public void welcome() {
        System.out.println("JMX 初體驗,So easy!");
    }
}複製程式碼

第三步:把實現的 MBean 註冊到 MBean 伺服器上,照著做就行啦,熟能生巧,莫糾結。

import javax.management.*;
import java.lang.management.ManagementFactory;

public class AppAgent {
    public static void main(String[] args) throws Exception {
        // 建立一個MBeanServer,用來管理MBean
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        // 建立AppMBean物件
        App mbean = new App();
        // 為AppMBean 建立ObjectName例項
        ObjectName name = new ObjectName("com.example.mbeans:type=App");
        // 將AppMbean物件註冊到MBeanServer上去
        mbs.registerMBean(mbean,name);

        // Wait forever
        System.out.println("Waiting forever...");
        Thread.sleep(Long.MAX_VALUE);
    }
}複製程式碼

第四步:通過 JDK 自帶工具或程式碼訪問定義的 MBean。


不妨先帶你們玩一下 JDK 自帶的 JConsole,開啟控制檯敲入命令:jconsole(前提是安裝了JDK),效果如下。



哎呦,我去效果確實不錯,什麼記憶體、執行緒、類以及 MBean 資訊應有盡有,自己私下可以著重關注 MBean資訊,觸發一下方法呼叫,說一千道一萬,不如自己點點看


趁著熱乎勁,再帶你們玩一下 JDK 自帶的 jvisualvm,開啟控制檯敲入命令:jvisualvm(前提也是安裝了 JDK),效果如下。




哎呦,我去,效果同樣槓槓滴,什麼記憶體、執行緒、類以及MBean資訊應有盡有,關鍵是長得也好看,誇一千道一萬,其實不妨自己點點看。


說實話,還真想多擼點程式碼,看一看效果。其實還是想再偷點懶,嘗試使用一下 sun 自己實現 jdmk 工具包 jmxtools,前方高能預警,有坑,有坑,不過先不填!


首先匯入 jmxtools 依賴包。

<dependency>    
    <groupId>com.sun.jdmk</groupId>
    <artifactId>jmxtools</artifactId>
    <version>1.2.1</version>
</dependency>複製程式碼

接著修改第三步中的 AppAgent,程式碼如下。

import com.sun.jdmk.comm.HtmlAdaptorServer;
import javax.management.*;
import java.lang.management.ManagementFactory;

public class AppAgent {
    public static void main(String[] args) throws Exception {
        // 建立一個MBeanServer,用來管理MBean
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

        // 建立AppMBean物件
        App mbean = new App();
        // 為AppMBean 建立ObjectName例項
        ObjectName name = new ObjectName("com.example.mbeans:type=App");
        // 將AppMbean物件註冊到MBeanServer上去
        mbs.registerMBean(mbean,name);

        // Wait forever
        //System.out.println("Waiting forever...");
        //Thread.sleep(Long.MAX_VALUE);

        //建立一個AdaptorServer,AdaptorServer也是一個MBean,提供MBean的HTML管理介面。
        ObjectName adapterName = new ObjectName("com.example.mbeans:name=htmladapter,port=8888");
        HtmlAdaptorServer adapter = new HtmlAdaptorServer(8888);
        mbs.registerMBean(adapter,adapterName);
        adapter.start();
    }
}複製程式碼

此時,坑已經備好,就等你來入坑,發現 jmxtools-1.2.1.jar 死活下載不下來,打破砂鍋追到底。

https://repo1.maven.org/maven2/com/sun/jdmk/jmxtools/1.2.1/jmxtools-1.2.1.jar複製程式碼

居然 Jar 包下載連結已經是 404 啦,Jar 包已經在茫茫宇宙中走丟啦!!!


那隻能通過野路子下載一個這樣的 Jar 包啦,然後在專案下建立 lib 目錄,並把 jmxtools-1.2.1.jar 包放進去,修改依賴為本地引入。

<!-- jmxtools -->
<dependency>
    <groupId>com.sun.jdmk</groupId>
    <artifactId>jmxtools</artifactId>
    <version>1.2.1</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/jmxtools-1.2.1.jar</systemPath>
</dependency>複製程式碼

然後再執行 AppAgent,訪問 http://localhost:8888/ 一探究竟。



其實看起來也挺爽,除了顏值差點勁,功能還湊合,二次包裝包裝應該也可以用。


4.

好了,跟著我的腳步一起走到這兒的,那絕對都是真愛啊!


不過此時你內心是否會有這樣的疑問:咱們既沒有定義獲取記憶體的方法,也沒有定義獲取執行緒等方法定義,但是頁面的這些資料從哪兒來的呢?


另外,當我們看原始碼時也會發現諸多 MXBean 的定義,到底 MXBean 又是啥呢?MBean 與 MXBean 啥區別呢?下圖摘自resin-4.0.55 的原始碼,會發現很多 MXBean 定義。



有疑問不可怕,本次的很多疑問先欠著你們。欲知答案如何,咱們且聽下回分解。


最後如果感覺有點幫助,不妨鍛鍊一下手指點個在看,或者再來個瘋狂分享轉發,因為你的每一次分享,我都認真當成了鼓勵與喜歡。

推薦閱讀:

玩弄日誌歸集於手掌之中

愛情36技之暗送秋波的技術

一篇文章講透線上應用監控