有人使用过远程 JMX JConsole 吗?

似乎我从来没有得到这个工作在过去。目前,我知道它不工作。

但是我们启动了 Java 进程:

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

我可以 telnet 到端口,并且“ something is there”(也就是说,如果我不启动进程,没有任何应答,但是如果我启动了,它会应答) ,但是我不能让 JConsole 填写 IP 和端口。

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

有人知道怎么做吗?

162496 次浏览

你在 Linux 上运行吗? 也许管理代理绑定到了 localhost:

Http://java.sun.com/j2se/1.5.0/docs/guide/management/faq.html#linux1

在测试/调试/诊断 遥控器 JMX 问题时,首先总是尝试连接到包含 MBeanServer 的同一主机(即本地主机) ,以排除网络和其他非 JMX 特定问题。

您可能遇到了防火墙问题。问题在于,您指定的端口不是唯一使用的端口,它为 RMI 使用了1个甚至2个以上的端口,并且这些端口可能被防火墙阻塞。

如果您使用默认的 RMI 配置,其中一个额外的端口将不会事先知道,因此您必须打开大范围的端口-这可能不会使服务器管理员感到高兴。

There is a solution that does not require opening up a lot of ports however, I've gotten it to work using the combined source snippets and tips from

http://forums.sun.com/thread.jspa?threadID=5267091 - link doesn't work anymore

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

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

甚至可以设置一个 ssh 隧道并仍然让它工作: -)

添加 -Djava.rmi.server.hostname='<host ip>'为我解决了这个问题。

我在 Windows 上运行 JConsole/JVisualVm,挂钩到运行 Linux Redhat ES3的 tomcat。

使用以下命令禁用信息包过滤对我来说很有效:

/usr/sbin/iptables -I INPUT -s jconsole-host -p tcp --destination-port jmxremote-port -j ACCEPT

where jconsole-host is either the hostname or the host address on which JConsole runs on and jmxremote-port is the port number set for com.sun.management.jmxremote.port for remote management.

您还需要确保您的机器名解析为 JMX 绑定到的 IP; NOT localhost 或127.0.0.1。对我来说,在主机中放入一个条目来明确定义这一点很有帮助。

让 JMX 通过防火墙真的很难。问题是标准 RMI 使用第二个随机分配的端口(在 RMI 注册表旁边)。

We have three solution that work, but every case needs a different one:

  1. JMX over SSH Tunnel with Socks proxy, uses standard RMI with SSH magic http://simplygenius.com/2010/08/jconsole-via-socks-ssh-tunnel.html

  2. JMX MP (alternative to standard RMI), uses only one fixed port, but needs a special jar on server and client Http://meteatamel.wordpress.com/2012/02/13/jmx-rmi-vs-jmxmp/

  3. Start JMX Server form code, there it is possible to use standard RMI and use a fixed second port: Https://issues.apache.org/bugzilla/show_bug.cgi?id=39055

I have a solution for this:

如果您的 Java 进程在防火墙后面的 Linux 上运行和您想在本地机器上的 Windows 上启动 JConsole/Java VisualVM/Java 任务控制以连接到 JMX Port of your Java process

您需要通过 SSH 登录访问您的 Linux 机器。所有通信将通过 SSH 连接隧道。

TIP: This Solution works no matter if there is a firewall or not.

缺点: 每次你使用 重新开始进行 Java 进程时,你都需要重新执行4-9步骤中的所有步骤。


1. 从这里开始,你需要为你的 Windows 机器准备油灰套件:

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 进程的 Process-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-Stubs。这个端口还需要通过 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. 使用腻子从 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

Example:

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


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


Settings to open an SSL tunnel via Putty


7. 在启用 SSH 隧道的情况下,用 Putty 登录到您的 Linux 机器。

让油灰阶段保持开启状态

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

JMX-Port:

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

RMIServer-存根-端口:

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


8. Start JConsole / Java VisualVM / Java Mission Control to connect to your Java Process using the following URL

这样可以工作,因为 JConsole/JavaVisualVM/Java 任务控制认为您连接到了本地 Windows 机器上的端口。但是 Putty 把所有的有效载荷发送到15666端口到你的 linux 机器上。

在 linux 机器上,java 进程首先给出答案,然后发送回 RMIServer 端口。

然后 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


Connect via jmx service url


9. 享受 # 8-]

Getting JMX through the firewall isn't that hard at all. There is one small catch. You have to forward both your JMX configured port ie. 9010 and one of dynamic ports its listens to on my machine it was > 30000

提示:

RMI 端口在任意 portnr 上打开。如果您有一个防火墙,并且不想打开端口1024-65535(或使用 vpn) ,那么您需要执行以下操作。

您需要修复 RMI 注册表和 JMX/RMI 服务器端口(因为有一个已知的号码)。您可以通过在 lib-dir 中放入一个 jar-file (catalina-jmx-Remote.jar,它在附加文件中)并在服务器下配置一个特殊的侦听器来完成这项工作:

<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> \

参见: http://tomcat.apache.org/tomcat-6.0-doc/config/listeners.html上的 JMX 远程生命周期监听器

然后你可以用这个可怕的网址连接:

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

After putting my Google-fu to the test for the last couple of days, I was finally able to get this to work after compiling answers from Stack Overflow and this page http://help.boomi.com/atomsphere/GUID-F787998C-53C8-4662-AA06-8B1D32F9D55B.html.

从戴尔 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

在我的例子中,我试图检索卡夫卡指标,所以我只是更改了上面的选项以匹配 -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)

这里已经有一些很好的答案,但是,有一个稍微简单的方法,我认为值得分享。

Sushicutta 的方法是好的,但是非常手动,因为你必须得到 RMI 端口每一次。幸运的是,我们可以通过使用 SOCKS 代理而不是显式地打开端口隧道来解决这个问题。这种方法的缺点是您在机器上运行的 JMX 应用程序需要能够配置为使用代理。大多数进程可以通过添加 java 属性来实现这一点,但是,一些应用程序不支持这一点。

Steps:

  1. 将 JMX 选项添加到远程 Java 服务的启动脚本:

    -Dcom.sun.management.jmxremote=true
    -Dcom.sun.management.jmxremote.port=8090
    -Dcom.sun.management.jmxremote.ssl=false
    -Dcom.sun.management.jmxremote.authenticate=false
    
  2. Set up a SOCKS proxy connection to your remote machine:

    ssh -D 9696 user@remotemachine.com
    
  3. Configure your local Java monitoring app to use the SOCKS proxy (localhost:9696). Note: You can sometimes do this from the command line, i.e.:

    jconsole -J-DsocksProxyHost=localhost -J-DsocksProxyPort=9696
    

这些步骤对我有效(服务器端防火墙后面的 debian,通过本地 Mac 的 VPN 访问) :

检查服务器 IP 地址

hostname -i

使用 JVM 参数:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=[jmx port]
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=[server ip from step 1]

运行应用程序

查找正在运行的 java 进程的 pid

检查 JMX/RMI 使用的所有端口

netstat -lp | grep [pid from step 4]

打开防火墙上步骤5的所有端口

瞧。

我使用 boot2docker 运行 Tomcat 内置的 docker 容器,我遇到了同样的问题,解决方案是:

  • Add -Djava.rmi.server.hostname=192.168.59.103
  • 在主机容器和多克容器中使用相同的 JMX 端口,例如: docker run ... -p 9999:9999 ...。使用不同的端口是不起作用的。

Check if your server is behind the firewall. JMX is base on RMI, which open two port when it start. One is the register port, default is 1099, and can be specified by the com.sun.management.jmxremote.port option. The other is for data communication, and is random, which is what cause problem. A good news is that, from JDK6, this random port can be specified by the com.sun.management.jmxremote.rmi.port option.

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"

为了做出贡献,这是我在 CentOS 6.4中为 Tomcat 6所做的。

  1. Shutdown iptables service

    service iptables stop
    
  2. Add the following line to tomcat6.conf

    CATALINA_OPTS="${CATALINA_OPTS} -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8085 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=[host_ip]"
    

This way I was able to connect from another PC using JConsole.

尝试使用 Java8和更新的版本

这个解决方案也可以很好地与防火墙一起工作

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. Execute this on your computer.

  • 视窗用户 :

    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. : 在步骤2中,使用 ssh-L指定本地(客户机)主机上的端口1616必须转发到远程端。这是一个 ssh 通道,有助于避免防火墙或各种网络问题。

Sushicutta 的步骤4-7可以通过在步骤3中添加以下代码来跳过:

-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 连接使用隧道。否则它可能会尝试直接连接并攻击防火墙。

我正在尝试运行 JMC 的飞行记录器(JFR)来配置远程服务器上的 NiFi,这个远程服务器不提供运行 JMC 的图形环境。

基于这里给出的其他答案,经过反复试验,以下是我在启动 NiFi 时向 JVM (Conf/bootstrap.conf)提供的内容:

java.arg.90=-Dcom.sun.management.jmxremote=true
java.arg.91=-Dcom.sun.management.jmxremote.port=9098
java.arg.92=-Dcom.sun.management.jmxremote.rmi.port=9098
java.arg.93=-Dcom.sun.management.jmxremote.authenticate=false
java.arg.94=-Dcom.sun.management.jmxremote.ssl=false
java.arg.95=-Dcom.sun.management.jmxremote.local.only=false
java.arg.96=-Djava.rmi.server.hostname=10.10.10.92  (the IP address of my server running NiFi)

我确实把它放进了 /etc/hosts,尽管我怀疑它是否有必要:

10.10.10.92   localhost

然后,在启动 JMC 之后,我用这些属性创建了一个远程连接:

Host: 10.10.10.92
Port: 9098
User: (nothing)
Password: (ibid)

顺便说一句,如果我单击 Custom JMX service URL,我会看到:

service:jmx:rmi:///jndi/rmi://10.10.10.92:9098/jmxrmi

这终于帮了我大忙。

下面的代码对我很有用(尽管我认为端口2101并没有对此做出什么贡献) :

-Dcom.sun.management.jmxremote.port=2100
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.rmi.port=2101
-Djava.rmi.server.hostname=<IP_ADDRESS>OR<HOSTNAME>

我正在从一个远程机器连接到一个运行着 Docker 的服务器,该进程位于容器内。此外,我停止了防火墙 D,但我不认为这是问题,因为我可以远程到2100,即使防火墙打开。 希望能有帮助。