如何将 JMX 绑定到特定接口?
我目前正在使用 com.sun.management.jmxremote.*
属性启动 Java VM,以便我可以通过 JConsole 连接到它进行管理和监视。 不幸的是,它监听机器上的所有接口(IP 地址)。
在我们的环境中,经常会出现多个 Java VM 同时在一台机器上运行的情况。 虽然可以告诉 JMX 侦听不同的 TCP 端口(使用 com.sun.management.jmxremote.port ),但最好让 JMX 使用标准 JMX 端口并仅绑定到特定的 IP 地址(而不是全部)。
这将使我们更容易找出我们通过 JConsole 连接到哪个虚拟机(因为每个虚拟机实际上“拥有”自己的 IP 地址)。 有人知道如何让 JMX 监听单个 IP 地址或主机名吗?
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. Unfortunately, it listens on all interfaces (IP addresses) on the machine.
In our environment, there are often cases where there is more than one Java VM running on a machine at the same time. 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).
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). Has anyone figured out how to make JMX listen on a single IP address or hostname?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果其他人会因此而失去神经的话……10年后,他们终于修好了!
由于 Java 8u102
-Dcom.sun.management.jmxremote.host
绑定到所选 IP,请参阅:https://bugs.openjdk.java.net/browse/JDK-6425769
If anyone else will be losing his nerves with this ... After 10 years, they finally fixed it!
Since Java 8u102
-Dcom.sun.management.jmxremote.host
binds to the selected IPsee: https://bugs.openjdk.java.net/browse/JDK-6425769
费尔南多已经提供了我的博客文章的链接:)..这不是微不足道的。 您必须提供自己的 RMIServerSocketFactoryImpl 来在所需地址上创建套接字。
如果内部/外部接口是问题所在,并且您具有本地访问权限,那么设置本地防火墙可能会更容易。
Fernando already provided a link to my blog post :) ..it's not trivial. You have to provide your own RMIServerSocketFactoryImpl that creates sockets on the wanted address.
If internal/external interfaces are the problem and you have local access setting up a local firewall might be easier.
我还没有尝试过这个,但这可能会有所帮助。
这里的主要麻烦是没有简单的方法来指定主机 IP
JMX 要绑定到的地址,它总是绑定到所有接口。 这
“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 实例,并使用所有
默认端口完好无损(例如,8080 用于所有 JMX)。
}
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. 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.
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.
I've fixed this by patching the default JVM RMI socket factory that is
responsible for creating this server socket. It now supports the new
'com.sun.management.jmxremote.host' property.
To get this to work, save the Java code below into a file named
sun/rmi/transport/proxy/RMIDirectSocketFactory.java.
Compile and create jmx_patch.jar from it and place it into the tomcat lib/
folder.
You then need to add the following line to bin/setenv.sh:
CLASSPATH=$CLASSPATH:$CATALINA_HOME/lib/mx_patch.jar
add this option in tomcat instance start up
-Dcom.sun.management.jmxremote.host=192.168.100.100"
This will then bind the JMX service only to address 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.
You can now run multiple tomcat instances on a single host with all the
default ports intact (e.g. 8080 for JMX for all of them).
}
仅使用
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.ssl
和jmxremote.registry.ssl
值的任何其他组合,它将为两个端口正确使用给定的jmxremote.host
。例如,
它仍然会绑定到端口
1234
的所有接口,并仅针对随机jmxremote.rmi.port
绑定到interface1
。请注意,JMX 客户端首先连接到
jmxremote.port
,这是一个 RMI 注册表,它通过它接收实际的 JMX 服务器端口jmxremote.rmi.port
,因此客户端仍然只能通过 jmxremote.host 接口与实际的 JMX 服务器通信。 然而,RMI 注册表监听所有接口仍然是不可取的,因为当不同的虚拟机使用相同的jmxremote.port
值启动时,会导致端口冲突,就像本问题中的情况一样。When just using
com.sun.management.jmxremote.host
without changingcom.sun.management.jmxremote.ssl
(default istrue
) orcom.sun.management.jmxremote.registry.ssl
(default isfalse
) it will still bind to all interfaces forcom.sun.management.jmxremote.port
, and will usecom.sun.management.jmxremote.host
only forcom.sun.management.jmxremote.rmi.port
(which defaults to random port). Not sure why it is the case, it look like a bug. For any other combination of thesejmxremote.ssl
andjmxremote.registry.ssl
values, it will properly use the givenjmxremote.host
for both ports.For example, with
it will still bind to all interfaces for the port
1234
, and bind tointerface1
only for the randomjmxremote.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 portjmxremote.rmi.port
, so the client would still be able to talk to the actual JMX server only over thejmxremote.host
interface. 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 samejmxremote.port
value, as is the scenario in this question.尽管没有记录
com.sun.management.jmxremote.host
,但您至少需要设置com.sun.management.jmxremote.{host,port,ssl}
它至少可以在 OpenJDK 1.8.0_312 中工作。您(很可能)还需要设置
java.rmi.server.hostname
。 请记住,JMX 客户端首先连接到 jmxremot 主机和端口,然后从那里获取 RMI 主机和端口,最后将通过 RMI 连接到该主机和端口(如果您未设置 java.rmi)。 server.hostname jmx 客户端将获取的主机(ip)不会有该端口的任何侦听器(因为您只侦听 127.0.0.1)这是一个有效的示例,并不是我也禁用了身份验证和强制 IPv4:
netstat 的输出确认端口 222 仅绑定到 127.0.0.1,而不绑定到 0.0.0.0:
You will need to set at least
com.sun.management.jmxremote.{host,port,ssl}
, althoughcom.sun.management.jmxremote.host
is not documented it does work at least in the OpenJDK 1.8.0_312.You will (most likely) need to set also
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 thejava.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)Here is an example that works, not that I also disabled authentication and forced IPv4:
The output from netstat confirms that port 222 is bound to 127.0.0.1 only and not to 0.0.0.0:
我刚刚尝试了
-Dcom.sun.management.jmxremote.host=
和 openjdk 1.8,效果很好。 它绑定到该地址(根据 netstat)并且一切看起来都正确(并且有效)。
I just tried
-Dcom.sun.management.jmxremote.host=
with openjdk 1.8, and it works well. It binds to that addess (according to netstat) and all looks right (and works).
接受的答案很旧。 有迹象表明 Java 现在提供了一些选项来实现这一点。 例如,我已经看到:
...以及...
但是,至少在 jdk 1.7 下的我的系统上,这些似乎没有任何效果 - JMX 连接器仍然绑定到 *. 更新的答案(具有特定的适用版本)将不胜感激。 这应该很简单。
The accepted answer is pretty old. There are some indications that Java now provides some options to enable this. For instance I have seen:
...as well as...
However, at least on my system under jdk 1.7, these do not seem to have any effect - the JMX connector still binds to *. An updated answer (with specific applicable versions) would be much appreciated. This should be simple.