简体   繁体   English

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

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

I am currently starting my Java VM with the com.sun.management.jmxremote.* properties so that I can connect to it via JConsole for management and monitoring.我目前正在使用com.sun.management.jmxremote.*属性启动我的 Java VM,以便我可以通过 JConsole 连接到它以进行管理和监视。 Unfortunately, it listens on all interfaces (IP addresses) on the machine.不幸的是,它会监听机器上的所有接口(IP 地址)。

In our environment, there are often cases where there is more than one Java VM running on a machine at the same time.在我们的环境中,经常会出现一台机器上同时运行多个 Java VM 的情况。 While it's possible to tell JMX to listen on different TCP ports (using com.sun.management.jmxremote.port ), it would be nice to instead have JMX use the standard JMX port and just bind to a specific IP address (rather than all of them).虽然可以告诉 JMX 监听不同的 TCP 端口(使用com.sun.management.jmxremote.port ),但最好让 JMX 使用标准 JMX 端口并绑定到特定的 IP 地址(而不是所有地址)其中)。

This would make it much easier to figure out which VM we're connecting to via JConsole (since each VM effectively "owns" its own IP address).这将使确定我们通过 JConsole 连接到哪个 VM 变得容易得多(因为每个 VM 实际上“拥有”自己的 IP 地址)。 Has anyone figured out how to make JMX listen on a single IP address or hostname?有没有人想出如何让 JMX 监听单个 IP 地址或主机名?

If anyone else will be losing his nerves with this ... After 10 years, they finally fixed it!如果其他人会因为这个而失去神经...... 10年后,他们终于解决了!

Since Java 8u102 -Dcom.sun.management.jmxremote.host binds to the selected IP由于 Java 8u102 -Dcom.sun.management.jmxremote.host绑定到所选 IP

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

Fernando already provided a link to my blog post :) ..it's not trivial. Fernando 已经提供了我的博客文章的链接:) ..这不是微不足道的。 You have to provide your own RMIServerSocketFactoryImpl that creates sockets on the wanted address.您必须提供自己的 RMIServerSocketFactoryImpl 以在所需地址上创建套接字。

If internal/external interfaces are the problem and you have local access setting up a local firewall might be easier.如果内部/外部接口是问题并且您具有本地访问权限,则设置本地防火墙可能会更容易。

I haven't tried this but this may help.我没有试过这个,但这可能会有所帮助。

the main nuisance here was that there is no easy way to specify the host IP address for JMX to bind to, it would always bind to all interfaces.这里的主要麻烦是没有简单的方法来指定 JMX 绑定到的主机 IP 地址,它总是绑定到所有接口。 The 'java.rmi.server.hostname' property did not work and I didn't want to pick different ports for all the different instances on the same host. 'java.rmi.server.hostname' 属性不起作用,我不想为同一主机上的所有不同实例选择不同的端口。

Also, I didn't want to create my own RMIServerSocketFactory with all the complexities associated with it, I was after a simple patch to the existing code.此外,我不想创建自己的 RMIServerSocketFactory 并具有与之相关的所有复杂性,我正在对现有代码进行简单的修补。

I've fixed this by patching the default JVM RMI socket factory that is responsible for creating this server socket.我通过修补负责创建此服务器套接字的默认 JVM RMI 套接字工厂来解决此问题。 It now supports the new 'com.sun.management.jmxremote.host' property.它现在支持新的“com.sun.management.jmxremote.host”属性。

To get this to work, save the Java code below into a file named sun/rmi/transport/proxy/RMIDirectSocketFactory.java.要使其工作,请将下面的 Java 代码保存到名为 sun/rmi/transport/proxy/RMIDirectSocketFactory.java 的文件中。

Compile and create jmx_patch.jar from it and place it into the tomcat lib/ folder.从中编译并创建 jmx_patch.jar 并将其放入 tomcat lib/ 文件夹中。

You then need to add the following line to bin/setenv.sh:然后,您需要将以下行添加到 bin/setenv.sh:

CLASSPATH=$CLASSPATH:$CATALINA_HOME/lib/mx_patch.jar类路径=$类路径:$CATALINA_HOME/lib/mx_patch.jar

add this option in tomcat instance start up在tomcat实例启动时添加这个选项

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

This will then bind the JMX service only to address 192.168.100.100.这将仅将 JMX 服务绑定到地址 192.168.100.100。 The 2 other random RMI listening ports will still bind to all interfaces, but that is fine as they always pick a free port anyway.其他 2 个随机 RMI 侦听端口仍将绑定到所有接口,但这很好,因为无论如何它们总是会选择一个空闲端口。

You can now run multiple tomcat instances on a single host with all the default ports intact (eg 8080 for JMX for all of them).您现在可以在单个主机上运行多个 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);
  }

} }

When just using com.sun.management.jmxremote.host without changing com.sun.management.jmxremote.ssl (default is true ) or com.sun.management.jmxremote.registry.ssl (default is false ) it will still bind to all interfaces for com.sun.management.jmxremote.port , and will use com.sun.management.jmxremote.host only for com.sun.management.jmxremote.rmi.port (which defaults to random 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 (默认为随机端口)。 Not sure why it is the case, it look like a bug.不知道为什么会这样,它看起来像一个错误。 For any other combination of these jmxremote.ssl and jmxremote.registry.ssl values, it will properly use the given jmxremote.host for both ports.对于这些jmxremote.ssljmxremote.registry.ssl值的任何其他组合,它将为两个端口正确使用给定的jmxremote.host

For example, with例如,与

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

it will still bind to all interfaces for the port 1234 , and bind to interface1 only for the random jmxremote.rmi.port .它仍然会绑定到端口1234所有接口,并且只绑定到interface1的随机jmxremote.rmi.port

Note that a JMX client first connects to jmxremote.port , which is a RMI registry, over which it receives the actual JMX server port jmxremote.rmi.port , so the client would still be able to talk to the actual JMX server only over the jmxremote.host interface.请注意,JMX 客户端首先连接到jmxremote.port ,这是一个 RMI 注册中心,通过它接收实际的 JMX 服务器端口jmxremote.rmi.port ,因此客户端仍然只能通过jmxremote.host接口。 However it is still undesirable for the RMI registry to listen on all interfaces, since it will lead to port conflicts when different VMs are started with the same jmxremote.port value, as is the scenario in this question.然而,仍然不希望 RMI 注册表监听所有接口,因为当不同的 VM 以相同的jmxremote.port值启动时,这将导致端口冲突,就像这个问题中的场景一样。

You will need to set at least com.sun.management.jmxremote.{host,port,ssl} , although com.sun.management.jmxremote.host is not documented it does work at least in the OpenJDK 1.8.0_312.您至少需要设置com.sun.management.jmxremote.{host,port,ssl} ,尽管com.sun.management.jmxremote.host没有记录在案,但它至少在 OpenJDK 1.8.0_312 中有效。

You will (most likely) need to set also java.rmi.server.hostname .您(很可能)还需要设置java.rmi.server.hostname Remember that the JMX client first connect to the jmxremot host and port, then gets an RMI host and port from there, and finally will connect via RMI to that host and port, if you don't set the java.rmi.server.hostname the host (the ip) that the jmx client will obtain will not have any listener for that port (since you are only listening at 127.0.0.1)请记住,JMX 客户端首先连接到 jmxremot 主机和端口,然后从那里获取 RMI 主机和端口,最后将通过 RMI 连接到该主机和端口,如果您没有设置java.rmi.server.hostname jmx 客户端将获得的主机(ip)将没有该端口的任何侦听器(因为您只在 127.0.0.1 上侦听)

Here is an example that works, not that I also disabled authentication and forced IPv4:这是一个有效的示例,而不是我还禁用了身份验证并强制使用 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
  

The output from.netstat confirms that port 222 is bound to 127.0.0.1 only and not to 0.0.0.0:来自 .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

I just tried我刚试过

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

with openjdk 1.8, and it works well.使用 openjdk 1.8,它运行良好。 It binds to that addess (according to netstat) and all looks right (and works).它绑定到那个地址(根据 netstat)并且一切看起来都正确(并且有效)。

The accepted answer is pretty old.接受的答案很旧。 There are some indications that Java now provides some options to enable this.有一些迹象表明 Java 现在提供了一些选项来实现这一点。 For instance I have seen:比如我见过:

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

...as well as... ...也...

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

However, at least on my system under jdk 1.7, these do not seem to have any effect - the JMX connector still binds to *.但是,至少在 jdk 1.7 下的我的系统上,这些似乎没有任何影响 - JMX 连接器仍然绑定到 *. An updated answer (with specific applicable versions) would be much appreciated.更新的答案(具有特定的适用版本)将不胜感激。 This should be simple.应该很简单。

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

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