有人成功使用远程JMX JConsole吗?

128

过去似乎我从未让此工作。目前我知道它不起作用。

但我们启动了Java进程:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=6002
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

我可以telnet到端口,然后"有些东西在那里"(也就是说,如果我不启动该进程,则没有任何答案,但如果我启动它,则会有答案),但我无法让JConsole在填写IP和端口后工作。

看起来应该很简单,但没有错误,没有噪音,什么都没有。只是不起作用。

有人知道这个的窍门吗?


3
如果您正在使用 Tomcat,则可能需要尝试以下解决方案:https://dev59.com/3nM_5IYBdhLWcg3wslfs#6782309 - Hajo Thelen
5
你在这里忘记接受了什么吗@Will? - Gray
20个回答

131

我有一个解决方案:

如果您的Java进程在Linux防火墙后运行,并且您想要在Windows本地机器上启动JConsole / Java VisualVM / Java Mission Control来连接到您的Java进程的JMX端口

您需要通过SSH登录访问Linux机器。所有通信都将通过SSH连接进行隧道传输。

TIP: 无论是否有防火墙,此解决方案均有效。

缺点:每次重新启动Java进程时,您都需要再次执行4-9步骤。


1. 您需要从此处获取Windows机器的putty-suite:

http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

至少需要putty.exe


2. 在您的Linux机器上定义一个空闲端口:

<jmx-remote-port>

示例:

jmx-remote-port = 15666      

3. 在Linux机器上为Java进程添加参数

必须按照以下方式进行。如果按照下面的方式进行,它将适用于防火墙后面的Linux机器(这是因为有-Djava.rmi.server.hostname=localhost参数)。

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=<jmx-remote-port>
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.local.only=false
-Djava.rmi.server.hostname=localhost

示例:

java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=15666 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.local.only=false -Djava.rmi.server.hostname=localhost ch.sushicutta.jmxremote.Main

4. 获取你的Java进程的进程ID

ps -ef | grep <java-processname>

result ---> <process-id>

例子:

ps -ef | grep ch.sushicutta.jmxremote.Main

result ---> 24321


5. 找到用于下载RMIServer存根的任意端口

Java进程在Linux机器上打开一个新的TCP端口,此端口将用于下载RMI Server存根。此端口还需要通过SSH隧道可用,以便连接到Java虚拟机。

可以使用netstat -lp找到此端口,也可以使用lsof -i查看Java进程开放了哪个端口。

注意:每次启动Java进程时,此端口都会更改。

netstat -lp | grep <process-id>

tcp        0      0 *:<jmx-remote-port>     *:*     LISTEN      24321/java
tcp        0      0 *:<rmi-server-port>     *:*     LISTEN      24321/java


result ---> <rmi-server-port>

示例:

netstat -lp | grep 24321

tcp        0      0 *:15666     *:*     LISTEN      24321/java
tcp        0      0 *:37123     *:*     LISTEN      24321/java


result ---> 37123

6. 使用putty在Windows机器上开启两个SSH隧道

Source port: <jmx-remote-port>
Destination: localhost:<jmx-remote-port>
[x] Local       
[x] Auto       

Source port: <rmi-server-port>
Destination: localhost:<rmi-server-port>
[x] Local       
[x] Auto

示例:

Source port: 15666
Destination: localhost:15666
[x] Local       
[x] Auto       

Source port: 37123
Destination: localhost:37123
[x] Local       
[x] Auto


使用Putty打开SSL隧道的设置


7. 使用启用了SSH隧道的Putty登录到您的Linux机器。

保持Putty会话打开状态。

当您登录时,Putty将通过SSH端口22隧道传输所有TCP连接到Linux机器。

JMX端口:

Windows machine: localhost:15666   >>> SSH >>>   linux machine: localhost:15666

RMIServer-Stub-Port:

Windows Machine: localhost:37123   >>> SSH >>>   linux machine: localhost:37123

8. 启动 JConsole / Java VisualVM / Java Mission Control 并使用以下 URL 连接到您的 Java 进程

这可行,因为 JConsole / Java VisualVM / Java Mission Control 认为您连接到了本地 Windows 计算机上的端口。但是 Putty 将所有有效负载发送到 15666 端口到您的 linux 计算机。

在 linux 计算机上,首先 java 进程会回答并发送回 RMIServer 端口。在此示例中为 37123。

然后JConsole / Java VisualVM / Java Mission Control 认为它连接到 localhost:37123 ,Putty 将整个有效负载转发到 linux 计算机。

Java 进程回答并打开连接。

[x] Remote Process:
service:jmx:rmi:///jndi/rmi://localhost:<jndi-remote-port>/jmxrmi

例子:

[x] Remote Process:
service:jmx:rmi:///jndi/rmi://localhost:15666/jmxrmi


通过JMX服务URL连接


9. ENJOY #8-]


1
这里只是一个小问题 - 没有RMI无法进行JMX连接吗? - Kumar Vaibhav
6
我得到了一个提示,我们可以将rmi.port设置为固定的端口号,这样我们就可以为RMIServer存根下载设置任意端口。 这应该可以使用Java属性“com.sun.management.jmxremote.rmi.port = <rmi-server-port>”来实现。 看起来这是Oracle Java VM中未记录的功能。 - sushicutta
1
确实比设置密钥库和受信任的存储要方便得多。 - TechFanDan
同样的过程,但是在表中没有这样的对象。 - wener
2
@sushicutta,你能在你的回答中加入这个提示吗?它完美地运行了,并且可以删除第4到6步,但要注意转发端口必须与原始端口相同,同时jmx和rmi端口也必须相同。 - shabby
显示剩余5条评论

80

对于我来说,添加-Djava.rmi.server.hostname='<host ip>'解决了这个问题。


2
在我的情况下,我需要添加IP地址(-Djava.rmi.server.hostname=<ip>)。 hostname -i 给了我两个IP地址,正确的是列表中的第二个。 - Georgy Bolyuba
4
对我来说并没有解决这个问题。在同连接Windows之间的连接对我来说不是问题,但当我尝试连接从运行在SUSE上的Oracle JDK 1.6.024的Java服务到Windows上的JVM Jvisualvm.exe进行监控时,连接失败了。因此,我认为这个人的问题仍然没有得到解答。 - djangofan
这对我解决了问题。加上通常的3个设置(身份验证/端口/SSL),现在我可以远程连接了。虽然该盒子正在监听多个虚拟接口,但可能是因为没有指定主机而使jvm感到困惑。 - Nicholi
终于解决了我在我的OSX笔记本上连接jconsole的问题。谢谢。 - rado
什么鬼?如果服务器有动态IP怎么办?这没有任何意义!!到底是谁发明的这个东西?? - user3926784
我还需要添加-Dcom.sun.management.jmxremote.rmi.port=6002(请参见下面的答案:https://dev59.com/hHVC5IYBdhLWcg3w51hv#27512104) - asmaier

65

尝试使用Java 8及更新版本

该解决方案在防火墙上同样有效。

1. 将以下内容添加到您的远程主机Java启动脚本中:

-Dcom.sun.management.jmxremote.port=1616
-Dcom.sun.management.jmxremote.rmi.port=1616
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.local.only=false
-Djava.rmi.server.hostname=localhost

2. 在您的计算机上执行以下操作。

  • Windows 用户:

    putty.exe -ssh user@remote-host -L 1616:remote-host:1616

  • Linux 和 Mac 用户:

    ssh user@remote-host -L 1616:remote-host:1616

3. 在您的计算机上启动 jconsole

jconsole localhost:1616

4. 玩得开心!

P.S.: 在第二步中,使用ssh-L参数指定本地主机(客户端)的1616端口必须被转发到远程主机。这是一个ssh隧道,有助于避免防火墙或各种网络问题。


2
很遗憾Oracle没有提到“com.sun.management.jmxremote.rmi.port”和“java.rmi.server.hostname”。我猜那就是我的问题所在。 https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html - Rop
因为据我所知,这个问题与JMX无关,而是与RMI的工作方式有关。例如,在这种情况下,我在jmeter中遇到了相同的问题,它在其客户端/服务器实现中使用rmi。 - freedev
2
它有效。只是补充一下我的隧道使用经验:1)可以在“-L 1616:localhost:1616”中使用“localhost”2)无法更改源端口,即这将不起作用:“-L 9999:localhost:1616”。 - gargii
选择 JConsole 而不是 Java VisualVM / Java Mission Control 有什么原因吗? - user7294900
你应该添加这样的内容:putty.exe -ssh user@remote-host -L 1616:remote-host:1616,它会打开一个putty窗口并要求输入密码,然后什么也不会发生,但是它应该保持打开状态 :) - Heetola
我不知道为什么,在我的环境中端口1616可以工作,而9998、9123和1975则不能。尽管我使用SSH转发代理。 - Leos Literak

21

在过去的几天里,我经过一番搜索使用 Google 工具后,终于通过从 Stack Overflow 和这个页面 http://help.boomi.com/atomsphere/GUID-F787998C-53C8-4662-AA06-8B1D32F9D55B.html 汇编答案,最终成功让它起作用。

这是从 Dell Boomi 页面转载的:

To Enable Remote JMX on an Atom

If you want to monitor the status of an Atom, you need to turn on Remote JMX (Java Management Extensions) for the Atom.

Use a text editor to open the <atom_installation_directory>\bin\atom.vmoptions file.

Add the following lines to the file:

-Dcom.sun.management.jmxremote.port=5002
-Dcom.sun.management.jmxremote.rmi.port=5002
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

我还没有看到任何Stack Overflow答案涵盖的一行是

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

在我的情况下,我尝试检索Kafka指标,因此我只需更改上述选项以匹配-Dcom.sun.management.jmxremote.port值。因此,在没有任何身份验证的情况下,最基本的配置应该如下所示:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=(jmx remote port)

-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.rmi.port=(jmx remote port)
-Djava.rmi.server.hostname=(CNAME|IP Address)

2
为"Google-fu"加一 - kevinarpe
"com.sun.management.jmxremote.rmi.port" 对我来说也是关键。还可以参考这个答案:https://dev59.com/Zn3aa4cB1Zd3GeqPdG9I#22306586 - David
我不需要“com.sun.management.jmxremote.local.only”,所以我认为你的配置并不是真正的“最简配置”。 - David

19

你可能遇到了防火墙问题。问题在于,您指定的端口不是唯一使用的端口,它还使用了1或2个RMI端口,这些端口可能被防火墙阻塞。

如果使用默认的RMI配置,则其中一个额外的端口将无法预先知道,因此您必须打开一大批端口,这可能不会让服务器管理员感到愉快。

但是有一种解决方法不需要打开很多端口,我已经成功地使用了来自以下来源的组合源代码片段和技巧

http://forums.sun.com/thread.jspa?threadID=5267091 - 链接已失效

http://blogs.oracle.com/jmxetc/entry/connecting_through_firewall_using_jmx

http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html

甚至可以设置ssh隧道,仍然能够正常工作 :-)


2
我能够使用 http://simplygenius.com/2010/08/jconsole-via-socks-ssh-tunnel.html 中描述的别名,并设置 -Djava.rmi.server.hostname(如此回答中提到的)来解决防火墙问题。 - Damien
未来的读者请注意:forums.sun.com 的链接已经失效。 - CDspace
1
请注意,给未来的读者:blogs.oracle.com 的链接已失效。 - Grimlock

11

8
在第三步中添加以下代码即可跳过Sushicutta的4-7步骤:
-Dcom.sun.management.jmxremote.rmi.port=<same port as jmx-remote-port>

例如,将其添加到启动参数中:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=12345
-Dcom.sun.management.jmxremote.rmi.port=12345
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.local.only=false
-Djava.rmi.server.hostname=localhost

端口转发方面,使用以下方式进行连接:

ssh -L 12345:localhost:12345 <username>@<host>

如果您的主机是一个跳板,请在上述操作后在跳板上运行以下命令,以简单地链式转发端口:

ssh -L 12345:localhost:12345 <username>@<host2>

请注意,hostname=localhost 是必需的,以确保 jmxremote 告诉 rmi 连接使用隧道。否则,它可能会尝试直接连接并触发防火墙。

这个方法对我很有帮助: (1)我添加了缺失的JMX参数并重新启动应用程序 (2)然后在本地机器上运行 ssh -L <JMX_port>:localhost:<JMX_port> <remote_user>@<remote_host> (3)然后我使用以下命令连接到远程JMX: jconsole <remote_host>:<JMX_port> - Rib47

6

小贴士:

RMI端口是在随机端口号上打开的。如果您有防火墙并且不想打开1024-65535端口(或使用VPN),则需要执行以下操作。

您需要确定(即有已知数字)RMI注册表和JMX / RMI服务器端口。您可以通过将一个jar文件(catalina-jmx-remote.jar在extras中)放入lib-dir并在服务器下配置特殊的监听器来实现此目的。

<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
      rmiRegistryPortPlatform="10001" rmiServerPortPlatform="10002" />

(当然还有用于激活 JMX 的常规标志)
    -Dcom.sun.management.jmxremote  \
    -Dcom.sun.management.jmxremote.ssl=false \
    -Dcom.sun.management.jmxremote.authenticate=false \
    -Djava.rmi.server.hostname=<HOSTNAME> \

请参考以下网页了解 JMX 远程生命周期监听器:http://tomcat.apache.org/tomcat-6.0-doc/config/listeners.html

接下来,您可以使用以下可怕的 URL 进行连接:

service:jmx:rmi://<hostname>:10002/jndi/rmi://<hostname>:10001/jmxrmi

尝试使用额外的jar包进行了上述操作,可以看到指定的RMI端口正在侦听,但在使用VisualVM连接到JVM端口后仍然会使用随机端口。解决方法:使用'lsof -i'监视端口,并打开那些具有阻塞连接的端口。 - Joseph Lust

5

检查您的服务器是否在防火墙后面。 JMX基于RMI,在启动时打开两个端口。一个是注册端口,默认为1099,并可以由com.sun.management.jmxremote.port选项指定。另一个用于数据通信,是随机的,这就是问题所在。好消息是,从JDK6开始,可以通过com.sun.management.jmxremote.rmi.port选项指定此随机端口。

export CATALINA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8991 -Dcom.sun.management.jmxremote.rmi.port=8991 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"

4
穿越防火墙获取JMX非常困难。问题在于标准RMI使用第二个随机分配的端口(除了RMI注册表)。
我们有三种解决方案,但每种情况都需要不同的解决方案:
1.通过Socks代理的SSH隧道获取JMX,使用带有SSH魔法的标准RMI。 http://simplygenius.com/2010/08/jconsole-via-socks-ssh-tunnel.html 2.JMX MP(标准RMI的替代品),只使用一个固定端口,但需要服务器和客户端上的特殊jar。 http://meteatamel.wordpress.com/2012/02/13/jmx-rmi-vs-jmxmp/ 3.从代码中启动JMX服务器,这样可以使用标准RMI并使用固定的第二个端口: https://issues.apache.org/bugzilla/show_bug.cgi?id=39055

所有其他答案都应该是这个答案的补充 - ruruskyi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接