如何让JMX绑定到特定的接口?

时间:2008-12-01 17:45:08

标签: java rmi jmx jconsole

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

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

这样可以更容易地找出我们通过JConsole连接到哪个VM(因为每个VM实际上“拥有”自己的IP地址)。有没有人想出如何让JMX监听单个IP地址或主机名?

6 个答案:

答案 0 :(得分:22)

如果有其他人会因此而失去神经...... 10年后,他们终于解决了这个问题!

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

请参阅:https://bugs.openjdk.java.net/browse/JDK-6425769

答案 1 :(得分:8)

费尔南多已经提供了my blog post :)的链接..这不是微不足道的。您必须提供自己的RMIServerSocketFactoryImpl,在所需地址上创建套接字。

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

答案 2 :(得分:0)

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

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

另外,我不想创建自己的RMIServerSocketFactory 与之相关的复杂性,我是对现有代码的一个简单补丁。

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

要使其工作,请将下面的Java代码保存到名为的文件中 太阳/ RMI /运输/代理/ 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。另外两个 随机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);
  }

}

答案 3 :(得分:0)

我刚试过

-Dcom.sun.management.jmxremote.host =

使用openjdk 1.8,效果很好。它与该addess绑定(根据netstat),所有看起来都正确(并且有效)。

答案 4 :(得分: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 的所有接口,并且只绑定到随机 interface1jmxremote.rmi.port

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

答案 5 :(得分:-3)

接受的答案很古老。有一些迹象表明Java现在提供了一些选项来实现这一点。比如我见过:

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

......以及......

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

但是,至少在我的系统jdk 1.7下,这些似乎没有任何影响 - JMX连接器仍然绑定到*。将非常感谢更新的答案(具有特定的适用版本)。这个应该很简单。