最近在學習 JVM,其中涉及到效能、記憶體等指標分析需要使用工具分享,Java 提供了幾個視覺化工具來監控和管理 Java 應用,比如 Jconsole、JVisual、JMC,他們以圖形化的介面實時的監控程式各種效能指標以及記憶體、CPU 的使用情況。
Jconsole、JVisual、JMC 視覺化工具,呼叫本地監控直接使用對應的命令列即可,但 Linux 無法使用視覺化工具,Java 程式基本都部署到 Linux 伺服器。需要本地遠端呼叫伺服器,本文記錄一下遠端呼叫的一些步驟和遇到的坑。
JXM(Java Management Extensions) 是 Java 提供的一套標準 API,用於管理和監控 Java 應用程式的各種效能指標和使用情況。這裡主要使用遠端存取的功能。
JMX 啟動引數:
啟動 Java 程式一般有兩種方式:
無論是 jar 還是 war 包,都是將上面的設定引數用空格拼接起來,比如將上面的引數拼接:
Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=18088 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=34.126.141.21
新增到組態檔或者啟動引數中。
jar 包程式啟動一般為:
java -jar xxx.jar
新增引數後:
java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1808 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=34.126.141.21 -jar xxx.jar
在啟動檔案 catalina.sh 裡面新增:
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1808 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=34.126.141.21"
新增上面的設定之後,重啟 tomcat,再使用 Jconsole 遠端連線
使用 jconsole 遠端連線,一直連線不上:
先檢視本地埠是否開啟:
netstat -ntlp
埠已開啟:
tcp6 0 0 :::1808 :::* LISTEN 9087/java
再檢視是否是防火牆問題,使用埠掃描檢視,埠也開啟了:
埠開啟了,但是還是無法連線
找了很多網上的答案,大家都是抄來抄去的,都是上面的設定。最後才發現少了 rmi 設定。
新增 rmi 埠:
-Dcom.sun.management.jmxremote.rmi.port=1808
JMX 和 RMI,是兩種相關聯的技術,JMX 使用 RMI 作為遠端管理工具來管理和監控 Java 程式,RMI 為 JMX 提供了遠端連線所需的遠端呼叫和通訊機制。
新增了上面的設定,就能遠端監控 Java 服務了。
tomcat 啟動新增了設定之後,關閉 tomcat 服務時,就報錯了:
sun.management.AgentConfigurationError: java.rmi.server.ExportException: Port already in use: 18088; nested exception is:
java.net.BindException: Address already in use (Bind failed)
at sun.management.jmxremote.ConnectorBootstrap.exportMBeanServer(ConnectorBootstrap.java:800)
at sun.management.jmxremote.ConnectorBootstrap.startRemoteConnectorServer(ConnectorBootstrap.java:468)
at sun.management.Agent.startAgent(Agent.java:262)
at sun.management.Agent.startAgent(Agent.java:452)
Caused by: java.rmi.server.ExportException: Port already in use: 18088; nested exception is:
java.net.BindException: Address already in use (Bind failed)
at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:346)
at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:254)
at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:412)
at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:147)
at sun.rmi.server.UnicastServerRef.exportObject(UnicastServerRef.java:237)
at sun.management.jmxremote.ConnectorBootstrap$PermanentExporter.exportObject(ConnectorBootstrap.java:199)
at javax.management.remote.rmi.RMIJRMPServerImpl.export(RMIJRMPServerImpl.java:146)
at javax.management.remote.rmi.RMIJRMPServerImpl.export(RMIJRMPServerImpl.java:122)
at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:404)
at sun.management.jmxremote.ConnectorBootstrap.exportMBeanServer(ConnectorBootstrap.java:796)
簡單就是埠被佔用了,又去網上搜了很多答案,彙總了兩個解決方法:
這兩種方案都是治標不治本的方法,每次都要做多一點的操作,就顯得很繁瑣。
無論使用 startup.sh 啟動 tomcat 還是使用 shutdown.sh 關閉 tomcat 都會執行 catalina.sh 指令碼,所以關閉 tomcat 也會啟動埠,而啟動 tomcat 的時候已經開啟了埠,關閉的時候再開啟就報錯了。
只在啟動 tomcat 時新增 jmx 相關的設定,在 catalina.sh 新增判斷條件 if [ "$1" = "start" ]
:
if [ "$1" = "start" ] ; then
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=18088 -Dcom.sun.management.jmxremote.rmi.port=18088 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=34.126.141.211"
fi