繁体   English   中英

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

[英]How to have JMX bind to a specific interface?

我目前正在使用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 地址或主机名?

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

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

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

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

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

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

这里的主要麻烦是没有简单的方法来指定 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:

类路径=$类路径:$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);
  }

}

当仅使用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.port ,这是一个 RMI 注册中心,通过它接收实际的 JMX 服务器端口jmxremote.rmi.port ,因此客户端仍然只能通过jmxremote.host接口。 然而,仍然不希望 RMI 注册表监听所有接口,因为当不同的 VM 以相同的jmxremote.port值启动时,这将导致端口冲突,就像这个问题中的场景一样。

您至少需要设置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 jmx 客户端将获得的主机(ip)将没有该端口的任何侦听器(因为您只在 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 的 output 确认端口 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

我刚试过

-Dcom.sun.management.jmxremote.host=

使用 openjdk 1.8,它运行良好。 它绑定到那个地址(根据 netstat)并且一切看起来都正确(并且有效)。

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

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

...也...

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM