解决jmx远程调用无法连接的问题

2017/03/14 java

  最近同事在迁移一个老的应用到容器中去,这个应用里面使用了jmx服务,配置的调用地址如:service:jmx:rmi://172.20.32.36/jndi/rmi://172.20.32.36:1072/remoteRMI,迁移完成后使用 jmc 工具去测试连接,会发现连接失败,而这个现象很诡异,有的机器发布的容器可以连接成功。询问了开发人员,回复是这个 jmx 服务认机器,以前不在容器中部署也存在这个问题。这其实是一个没有答案的回复了,但没办法,我们必须要将这个应用部署到容器中,只能自己好好分析分析了,我相信在不同的机器使用镜像启动应该都是一致的,既然有机器可以使用,那么肯定是机器配置哪里有不一样。

排查步骤

  • 防火墙的问题:主监听端口设置了允许访问,但是随机端口号是 Java 进程启动后,OS 随机分配给 jmxserver 的,如果不关闭防火墙,就必须在每次 server 就绪后,检测一下随机端口,然后设置为允许访问。(我检查服务器防火墙都是关闭状态的,netstat 与 telnet 也都是正常的,可以排除被墙的问题)
netstat -ntlp |grep 1072
tcp6       0      0 :::1072                 :::*                    LISTEN      36496/java
telnet 172.20.32.36 1072
  • tomcat 启动 cataina.sh 时参数 CATALINA_OPTS 配置问题。(尝试增加配置后问题依旧)
      -Dcom.sun.management.jmxremote=true \
      -Dcom.sun.management.jmxremote.port="1072" \
      -Dcom.sun.management.jmxremote.ssl=false \
      -Dcom.sun.management.jmxremote.authenticate=false \
      -Djava.rmi.server.hostname=172.20.32.36 \
  • hostname 的问题:我比较了可用和不可用的 hostname 、/etc/hosts、/etc/resolv.conf 等文件,没有发现什么差异,这里有被误导,很多资料仅仅说 hostname 有问题,并没有说要怎么去查看哪里有问题,最开始用 hostname 检查肯定看不出问题,直到兜了一大圈回来,在一个测试论坛找到了答案,应该用 hostname -i 来检查,于是发现了差异。
[root@es-36 /]# hostname -i
127.0.0.1
[root@es-127 /]# hostname -i
172.20.32.127

那么问题来了,这个 hostname -i 又是从哪里取值的呢,其实很简单,就是在 /etc/hosts 配置的,如下:

[root@es-36 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
# 127.0.0.1    es-36
172.20.32.36   es-36
[root@es-36 ~]# hostname -i
172.20.32.36

将 127.0.0.1 修改为机器的物理 IP 发现 hostname -i 正常,jmx 服务也能正常访问了。

参考资料

JDK-6209663 : jconsole won’t connect to remote JVM on Linux

JVM启用JMX服务选项

Monitoring and Management Using JMX

JDK-8035404 : Java opens random 3-d port when JMX is configured

Why Java opens 3 ports when JMX is configured?

JMX through a ssh tunnel

设置不受保护的 JMX

在不使用 SSL 的情况下设置 JMX 以进行客户机认证

Monitoring and Management Using JMX Technology

jmx rmi 穿越防火墙问题及jmxmp的替代方案

通过【jmx rmi 穿越防火墙问题及jmxmp的替代方案】解决了随机端口产生的问题,原因就是:

JMXConnectorServer的JMXServiceURL为如下形式:service:jmx:rmi://localhost:5000/jndi/rmi://localhost:6000/jmxrmi 则首先客户端连接到rmiregistry上得到真实服务器的stub(如rmi://localhost:6000/rmxrmi),然后客户端再根据该stub连接到真实的服务器上(如rmi://localhost:5000)。如果jmx服务端省略了蓝色部分的标注,默认的通信端口是随机产生的。

解决办法:就是代码里面的连接要使用2个端口即可。哎,找了好久。经实测,这2个端口可以用同一个,在 docker 中使用实践通过哦,^ _ ^ 。

总结

  从这找错的过程来看,其实并不算太复杂,因为我算是 java 基础比较弱的,这个 jmx 也是第一次接触,但为什么我能找到专业开发人员都无法找出的问题呢?可能我比他们多一些耐心和钻研精神吧。我想对技术应该要有这种态度,多思考问题,才能将技术学习得更扎实。

转载请注明出处,本文采用 CC4.0 协议授权,版权归 Mars丶小石头 所有。

Search

    Table of Contents