Jconsole、JVisual、JMC 可视化工具,调用本地监控直接使用对应的命令行即可,但 Linux 无法使用可视化工具,Java 程序基本都部署到 Linux 服务器。需要本地远程调用服务器,本文记录一下远程调用的一些步骤和遇到的坑。

JMX

JXM(Java Management Extensions) 是 Java 提供的一套标准 API,用于管理和监控 Java 应用程序的各种性能指标和使用情况。这里主要使用远程访问的功能。

JMX 启动参数:

  • -Dcom.sun.management.jmxremote 远程开启开关
  • -Dcom.sun.management.jmxremote.port=1808 jmx远程调用端口
  • -Dcom.sun.management.jmxremote.authenticate=false 不开启验证
  • -Dcom.sun.management.jmxremote.ssl=false 不为ssl连接
  • -Djava.rmi.server.hostname=34.126.141.21 服务器所在ip或者域名

配置远程连接

启动 Java 程序一般有两种方式:

  • 一是打成 jar 包,使用 java -jar 运行程序。
  • 一种是打成 war 包,放在 tomcat 上运行。

无论是 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

添加到配置文件或者启动参数中。

Java 程序启动

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

tomcat 启动

在启动文件 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 远程连接,一直连接不上

Jconsole 开启远程连接遇到的一些坑-LMLPHP

无法远程问题排查

先查看本地端口是否开启:

netstat -ntlp

端口已开启:

tcp6     0     0 :::1808          :::*              LISTEN      9087/java

再查看是否是防火墙问题,使用端口扫描查看,端口也开启了:

Jconsole 开启远程连接遇到的一些坑-LMLPHP

端口开启了,但是还是无法连接

找了很多网上的答案,大家都是抄来抄去的,都是上面的配置。最后才发现少了 rmi 配置。

解决方案

添加 rmi 端口:

-Dcom.sun.management.jmxremote.rmi.port=1808

添加了上面的配置,就能远程监控 Java 服务了。

关闭 tomcat 报错

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)

简单就是端口被占用了,又去网上搜了很多答案,汇总了两个解决方法:

  • 把 catalina.sh 添加的配置删掉
  • 使用 kill -9 的命令直接杀掉进程

这两种方案都是治标不治本的方法,每次都要做多一点的操作,就显得很繁琐。

问题分析

无论使用 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

总结

  • 网上都是相互抄来抄去的,都是缺少 RMI 配置,完整配置如下
    • JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1808 -Dcom.sun.management.jmxremote.rmi.port=1808 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=34.126.141.21"
  • JMX 是一套标准 API,用于管理和监控 Java 应用程序。而 RMI 为 JMX 提供了远程连接。
  • 关闭的报错的解决方案也是互相抄来抄去,解决方案都是治标不治本。在配置上面添加 if 判断条件 添加判断条件 if [ "$1" = "start" ]。
06-20 21:28