23

我目前正在使用com.sun.management.jmxremote.*属性启动我的 Java VM,以便我可以通过 JConsole 连接到它以进行管理和监视。不幸的是,它侦听机器上的所有接口(IP 地址)。

在我们的环境中,经常会出现在一台机器上同时运行多个 Java VM 的情况。虽然可以告诉 JMX 监听不同的 TCP 端口(使用com.sun.management.jmxremote.port),但最好让 JMX 使用标准 JMX 端口并绑定到特定的 IP 地址(而不是全部)。

这将使我们更容易确定我们通过 JConsole 连接到哪个 VM(因为每个 VM 有效地“拥有”自己的 IP 地址)。有没有人想出如何让 JMX 监听单个 IP 地址或主机名?

4

7 回答 7

31

如果其他人会因此而失去神经... 10年后,他们终于修好了!

由于 Java 8u102-Dcom.sun.management.jmxremote.host绑定到选定的 IP

见:https ://bugs.openjdk.java.net/browse/JDK-6425769

于 2016-09-06T09:11:20.793 回答
8

Fernando 已经提供了我的博客文章的链接:) .. 这不是微不足道的。您必须提供您自己的 RMIServerSocketFactoryImpl 以在所需地址上创建套接字。

如果内部/外部接口是问题,并且您具有本地访问权限,则设置本地防火墙可能会更容易。

于 2008-12-02T01:51:39.640 回答
0

我没有尝试过,但这可能会有所帮助。

这里的主要麻烦是没有简单的方法来指定 JMX 绑定到的主机 IP 地址,它总是绑定到所有接口。'java.rmi.server.hostname' 属性不起作用,我不想为同一主机上的所有不同实例选择不同的端口。

此外,我不想创建自己的 RMIServerSocketFactory 并具有与之相关的所有复杂性,我是在对现有代码进行简单修补之后。

我已通过修补负责创建此服务器套接字的默认 JVM RMI 套接字工厂来解决此问题。它现在支持新的“com.sun.management.jmxremote.host”属性。

要使其工作,请将下面的 Java 代码保存到名为 sun/rmi/transport/proxy/RMIDirectSocketFactory.java 的文件中。

编译并从中创建 jmx_patch.jar 并将其放入 tomcat lib/ 文件夹中。

然后,您需要将以下行添加到 bin/setenv.sh:

CLASSPATH=$CLASSPATH:$CATALINA_HOME/lib/mx_patch.jar

在 tomcat 实例启动中添加此选项

-Dcom.sun.management.jmxremote.host=192.168.100.100"

这会将 JMX 服务仅绑定到地址 192.168.100.100。其他 2 个随机 RMI 侦听端口仍将绑定到所有接口,但这很好,因为它们总是选择一个空闲端口。

您现在可以在单个主机上运行多个 tomcat 实例,并且所有默认端口都完好无损(例如,所有这些端口的 JMX 为 8080)。

package sun.rmi.transport.proxy;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.server.RMISocketFactory;

public class RMIDirectSocketFactory extends RMISocketFactory {

    public Socket createSocket(String host, int port) throws IOException
    {
     return new Socket(host, port);
    }

   public ServerSocket createServerSocket(int port) throws IOException
   {
   String jmx_host = System.getProperty("com.sun.management.jmxremote.host");
   String jmx_port = System.getProperty("com.sun.management.jmxremote.port");

  // Allow JMX to bind to specific address
  if (jmx_host != null && jmx_port != null && port != 0 && integer.toString(port).equals(jmx_port)) {
    InetAddress[] inetAddresses = InetAddress.getAllByName(jmx_host);
    if (inetAddresses.length > 0) {
    return new ServerSocket(port, 50, inetAddresses[0]);
   }
}

 return new ServerSocket(port);
  }

}

于 2016-08-09T19:45:02.410 回答
0

当仅使用com.sun.management.jmxremote.host而不更改com.sun.management.jmxremote.ssl(默认为true)或com.sun.management.jmxremote.registry.ssl(默认为false)时,它仍将绑定到所有接口com.sun.management.jmxremote.port,并且com.sun.management.jmxremote.host仅用于com.sun.management.jmxremote.rmi.port(默认为随机端口)。不知道为什么会这样,它看起来像一个错误。对于这些jmxremote.ssljmxremote.registry.ssl值的任何其他组合,它将正确使用给定jmxremote.host的两个端口。

例如,与

  -Dcom.sun.management.jmxremote.authenticate=false
  -Dcom.sun.management.jmxremote.port=1234
  -Dcom.sun.management.jmxremote.host=interface1
  

它仍然会绑定到端口的所有接口1234,并且只绑定到interface1随机的jmxremote.rmi.port

请注意,JMX 客户端首先连接到jmxremote.portRMI 注册表,通过它接收实际的 JMX 服务器端口jmxremote.rmi.port,因此客户端仍然只能通过jmxremote.host接口与实际的 JMX 服务器通信。但是,RMI 注册表仍然不希望监听所有接口,因为当不同的 VM 以相同的jmxremote.port值启动时会导致端口冲突,就像这个问题中的场景一样。

于 2021-07-24T05:59:46.777 回答
0

您将需要至少设置com.sun.management.jmxremote.{host,port,ssl},尽管com.sun.management.jmxremote.host没有记录它至少在 OpenJDK 1.8.0_312 中确实有效。

您(很可能)还需要设置java.rmi.server.hostname. 请记住,JMX 客户端首先连接到 jmxremot 主机和端口,然后从那里获取 RMI 主机和端口,最后将通过 RMI 连接到该主机和端口,如果您不设置java.rmi.server.hostname主机(IP) jmx 客户端将不会有该端口的任何侦听器(因为您只在 127.0.0.1 侦听)

这是一个有效的示例,并不是说我也禁用了身份验证并强制使用 IPv4:

/usr/lib/jvm/java-8-openjdk-amd64//bin/java \
-Dcom.sun.management.jmxremote.host=127.0.0.1  \
-Djava.rmi.server.hostname=127.0.0.1 \
-Dcom.sun.management.jmxremote.port=2222 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.registry.ssl=false  \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.net.preferIPv4Stack=true \
-jar your-uber.jar
  

netstat 的输出确认端口 222 仅绑定到 127.0.0.1 而不是 0.0.0.0:

netstat -plnt|grep 2222
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:2222          0.0.0.0:*               LISTEN      15390/java
于 2022-02-28T16:43:07.660 回答
-2

我刚试过

-Dcom.sun.management.jmxremote.host=

使用openjdk 1.8,效果很好。它绑定到那个地址(根据 netstat)并且看起来一切正常(并且有效)。

于 2017-03-19T21:38:09.383 回答
-3

接受的答案很老了。有一些迹象表明 Java 现在提供了一些选项来启用此功能。例如我见过:

-Djava.rmi.server.hostname=<YOUR_IP>

...也...

-Dcom.sun.management.jmxremote.host=<YOUR_IP>

但是,至少在我的 jdk 1.7 下的系统上,这些似乎没有任何作用——JMX 连接器仍然绑定到 *. 更新的答案(带有特定的适用版本)将不胜感激。这应该很简单。

于 2014-09-15T19:11:38.947 回答