Java 6 是否为 JMX 远程连接打开默认端口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/516142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does Java 6 open a default port for JMX remote connections?
提问by Bob Cross
My specific question has to do with JMX as used in JDK 1.6: if I am running a Java process using JRE 1.6 with
我的具体问题与 JDK 1.6 中使用的 JMX 有关:如果我正在使用 JRE 1.6 运行 Java 进程
com.sun.management.jmxremote
in the command line, does Java pick a default port for remote JMX connections?
在命令行中,Java 是否为远程 JMX 连接选择默认端口?
Backstory: I am currently trying to develop a procedure to give to a customer that will enable them to connect to one of our processes via JMX from a remote machine. The goal is to facillitate their remote debugging of a situation occurring on a real-time display console. Because of their service level agreement, they are strongly motivated to capture as much data as possible and, if the situation looks too complicated to fix quickly, to restart the display console and allow it to reconnect to the server-side.
背景故事:我目前正在尝试开发一个程序来提供给客户,使他们能够从远程机器通过 JMX 连接到我们的一个进程。目标是促进他们对实时显示控制台上发生的情况进行远程调试。由于他们的服务级别协议,他们强烈要求捕获尽可能多的数据,如果情况看起来太复杂而无法快速修复,则重新启动显示控制台并允许其重新连接到服务器端。
I am aware the I could run jconsoleon JDK 1.6 processes and jvisualvmon post-JDK 1.6.7 processes given physical access to the console. However, because of the operational requirements and people problems involved, we are strongly motivated to grab the data that we need remotely and get them up and running again.
我知道我可以在 JDK 1.6 进程上运行jconsole,并在 JDK 1.6.7 之后的进程上运行jvisualvm,只要物理访问控制台。然而,由于涉及操作要求和人员问题,我们有强烈的动机远程获取我们需要的数据并让它们重新启动和运行。
EDIT: I am aware of the command line port property
编辑:我知道命令行端口属性
com.sun.management.jmxremote.port=portNum
The question that I am trying to answer is, if you do not set that property at the command line, does Java pick another port for remote monitoring? If so, how could you determine what it might be?
我要回答的问题是,如果您没有在命令行中设置该属性,Java 是否会选择另一个端口进行远程监控?如果是这样,你如何确定它可能是什么?
采纳答案by Eddie
The documentationsuggests that the JMX agent uses a localport -- something unreachable from outside the machine -- unless you specify the following property:
该文件表明,JMX代理使用本地港口-这是从无法访问外机-除非您指定以下属性:
com.sun.management.jmxremote.port=portNum
com.sun.management.jmxremote.port=portNum
This is for security reasons, as well as for the reason given by Mr Potato Head. Thus, it looks like Java 6 does not open a default remotely accessibleport for JMX.
这是出于安全原因,也是出于土豆头先生给出的原因。因此,看起来 Java 6 没有为 JMX打开默认的远程访问端口。
EDIT: Added after the OP added an answer with more information.
编辑:在 OP 添加了包含更多信息的答案之后添加。
Another option you have is to somehow create a local proxy that listens to all local JMX connections and exports this information. This way, you don't need to have such magic configuration of each JVM instance on the server. Instead the local proxy can connect to all JVMs via JMX and then somehow expose this information remotely. I am not positive exactly how you would implement this, but something like this may be less work than what you otherwise have to do to expose all of your JVMs remotely via JMX.
您拥有的另一个选择是以某种方式创建一个本地代理,以侦听所有本地 JMX 连接并导出此信息。这样,您就不需要对服务器上的每个 JVM 实例进行如此神奇的配置。相反,本地代理可以通过 JMX 连接到所有 JVM,然后以某种方式远程公开此信息。我不确定您将如何实现这一点,但与您通过 JMX 远程公开所有 JVM 所需的工作相比,这样的工作可能要少得多。
回答by David Grant
The documentationseems to indicate that the JMX agent uses a local ephemeral port, unlessyou specify the following property:
该文档似乎表明 JMX 代理使用本地临时端口,除非您指定以下属性:
com.sun.management.jmxremote.port=portNum
Default ports are avoided because you could have manyjava applications on one system, and if there was a default port, only one application would be able to be managed! The above configuration property is provided for the express purposeof remotemanagement.
避免使用默认端口,因为您可以在一个系统上拥有多个Java 应用程序,如果有默认端口,则只能管理一个应用程序!根据上述结构,属性设置为明确目的的远程管理。
If you must insist on using an ephemeral port, then the URL of the JMX agent should be accessible from within the JVM, through the following system property (although this is likely to be a local address):
如果您必须坚持使用临时端口,那么 JMX 代理的 URL 应该可以从 JVM 内部通过以下系统属性访问(尽管这可能是本地地址):
com.sun.management.jmxremote.localConnectorAddress
Note: I guess you could always open a socket on a remotely-available address and proxy requests on to the local socket, but using the available option seems far more attractive!
注意:我猜你总是可以在远程可用地址上打开一个套接字,并将代理请求发送到本地套接字,但使用可用选项似乎更具吸引力!
回答by Bob Cross
So, the short answer to my question is "no."
所以,对我的问题的简短回答是“不”。
However, it's interesting to examine why. Look at the netstat
output from a valid local connection. Here are the ports that I see opened up as a result of a jconsole
making a local connection to itself. As you can see, port 1650 is the local port being used for the JMX information:
然而,研究原因很有趣。查看netstat
有效本地连接的输出。以下是我看到由于jconsole
与自身建立本地连接而打开的端口。如您所见,端口 1650 是用于 JMX 信息的本地端口:
Proto Local Address Foreign Address State
TCP Gandalf:1650 Gandalf:1652 ESTABLISHED
TCP Gandalf:1650 Gandalf:1653 ESTABLISHED
TCP Gandalf:1650 Gandalf:1654 ESTABLISHED
TCP Gandalf:1650 Gandalf:1655 ESTABLISHED
TCP Gandalf:1650 Gandalf:1656 ESTABLISHED
TCP Gandalf:1652 Gandalf:1650 ESTABLISHED
TCP Gandalf:1653 Gandalf:1650 ESTABLISHED
TCP Gandalf:1654 Gandalf:1650 ESTABLISHED
TCP Gandalf:1655 Gandalf:1650 ESTABLISHED
TCP Gandalf:1656 Gandalf:1650 ESTABLISHED
However, it's not sufficient to try to connect jconsole
to localhost:1650
. Sadly, all that will net you is a "Connection failed: no such object in table" message.
但是,尝试连接jconsole
到localhost:1650
. 可悲的是,所有的结果都是“连接失败:表中没有这样的对象”消息。
So, the conclusion of my original story is that, if we are going to facilitate remote monitoring using JMX for our customers, we really need to identify unique individual remote access ports for the variety of Java processes that are started in our system. Fortunately, all this requires is the judicious use of the VM argument:
所以,我原来的故事的结论是,如果我们要为我们的客户使用 JMX 促进远程监控,我们真的需要为我们系统中启动的各种 Java 进程识别唯一的单独远程访问端口。幸运的是,这一切都需要明智地使用 VM 参数:
com.sun.management.jmxremote.port=portNum
where we will almost certainly have a sequential pre-specified range of portNum
so that the customer can select the correct remote application using the port number.
我们几乎肯定会有一个连续的预先指定的范围,portNum
以便客户可以使用端口号选择正确的远程应用程序。
回答by David Tonhofer
AFAIK,
AFAIK,
Here are the possibilites for connecting a JMX client process(a management applicationlike jconsole, jmxterm, mc4j, jvmstat, jmxmonitor, jps, ...) to a JMX server process(the agent).
以下是将JMX 客户端进程(jconsole、jmxterm、mc4j、jvmstat、jmxmonitor、jps 等管理应用程序)连接到JMX 服务器进程(代理)的可能性。
The protocol connecting JMX client and JMX server is assumed to be 'Java RMI' (aka 'RMI-JRMP'). This should be the default. One can configure other protocols, in particular 'RMI-IIOP' and 'JMXMP'. Special protocols are possible: the MX4Jproject for example additionally provides SOAP/HTTP and various serialization protocols over HTTP.
假设连接 JMX 客户端和 JMX 服务器的协议是“Java RMI”(又名“RMI-JRMP”)。这应该是默认值。可以配置其他协议,特别是“RMI-IIOP”和“JMXMP”。特殊协议是可能的:例如MX4J项目额外提供了 SOAP/HTTP 和基于 HTTP 的各种序列化协议。
Refer to Sun/Oracle docsfor details on configuration.
有关配置的详细信息,请参阅Sun/Oracle 文档。
Also have a look at the file jre/lib/management/management.properties
in your JDK distribution.
还可以查看jre/lib/management/management.properties
JDK 发行版中的文件。
So, the possibilities:
所以,可能性:
Case 0: The JVM is started without any particular configuration
案例 0:JVM 在没有任何特定配置的情况下启动
Before Java 6: The JVM does not behave as a JMX server. Any program that is run inside the JVM may access the JVM's MBeanServerprogrammatically and use it to do interesting data exchanges between threads or to do JVM monitoring, but no management from outside the JVM process is possible.
在 Java 6 之前:JVM 的行为不像 JMX 服务器。任何在 JVM 内部运行的程序都可以以编程方式访问 JVM 的MBeanServer并使用它在线程之间进行有趣的数据交换或进行 JVM 监控,但无法从 JVM 进程外部进行管理。
Since Java 6: Even if not explicitely configured, one can access JMX functionality of the JVM locally(from the same machine) as described in "Case 1".
从 Java 6 开始:即使没有明确配置,也可以在本地(从同一台机器)访问 JVM 的 JMX 功能,如“案例 1”中所述。
Case 1: The JVM is started with -Dcom.sun.management.jmxremote
案例1:JVM启动 -Dcom.sun.management.jmxremote
The JVM is configured to work as a local(same-machine-only) JMX server.
JVM 配置为作为本地(仅限同一机器)JMX 服务器工作。
In this case (and in principle only for Sun/Oracle JVMs) a JMX client can connect to the JMX server through memory-mapped files found in /tmp/hsperfdata_[user]
. This is alluded to in the Sun documentation and called "local monitoring" (and also the Attach API). It does not work on FAT filesystems as permissions cannot be set correctly there. See this blog entry.
在这种情况下(原则上仅适用于 Sun/Oracle JVM),JMX 客户端可以通过/tmp/hsperfdata_[user]
. 这在 Sun 文档中被提及并称为“本地监控”(以及附加 API)。它不适用于 FAT 文件系统,因为在那里无法正确设置权限。请参阅此博客条目。
Sun recommends running jconsole
on a machine separate from the JMX server as jconsole
apparently is a resource hog, so this "local monitoring" thing is not necessarily a good idea.
Sun 建议jconsole
在与 JMX 服务器分开的机器上运行,因为这jconsole
显然是一种资源浪费,所以这种“本地监控”不一定是一个好主意。
Local monitoring is, however, rather secure, only being usable locally and being easily controlled through filesystem permissions.
然而,本地监控相当安全,只能在本地使用并且可以通过文件系统权限轻松控制。
Case 2: The JMX server is started with -Dcom.sun.management.jmxremote.port=[rmiregistryport]
案例2:JMX服务器启动 -Dcom.sun.management.jmxremote.port=[rmiregistryport]
The JVM is configured to work as a JMX server listening on several TCP ports.
JVM 配置为用作侦听多个 TCP 端口的 JMX 服务器。
The port specified on the command line will be allocated by the JVM and an RMI registry will be available there. The registry advertises a connector named 'jmxrmi'. It points to a second, randomly allocated TCP port (an 'ephemeral' port) on which the JMX RMI server listens and through which actual data exchange takes place.
在命令行上指定的端口将由 JVM 分配,并且 RMI 注册表将在那里可用。注册表通告了一个名为“jmxrmi”的连接器。它指向第二个随机分配的 TCP 端口(一个“临时”端口),JMX RMI 服务器在该端口上进行侦听并通过该端口进行实际的数据交换。
Local as described in 'Case 1' is always enabled in 'Case 2'.
在“案例 2”中始终启用“案例 1”中描述的本地。
The JMX server listens on all interfaces by default, so you can connect to it (and control it) by locally connecting to 127.0.0.1:[rmiregistryport] as well by remotely connecting to [any outside IP address]:[some port] remotely.
JMX 服务器默认侦听所有接口,因此您可以通过本地连接到 127.0.0.1:[rmiregistryport] 以及远程连接到 [任何外部 IP 地址]:[某个端口] 远程连接到它(并控制它) .
This implies that you have to look at the security implications. You can make the JVM listen on 127.0.0.1:[rmiregistryport] only by setting -Dcom.sun.management.jmxremote.local.only=true
.
这意味着您必须查看安全隐患。你可以让 JVM 监听 127.0.0.1:[rmiregistryport] 只能通过设置-Dcom.sun.management.jmxremote.local.only=true
.
It is rather unfortunate that one cannot specify where the ephemeral port will be allocated - it is always chosen randomly at startup. This may well mean that your firewall needs to become the swiss cheese of the damned! However, there are workarounds. In particular, Apache Tomcat sets the ephemeral JMX RMI server port via its JMX Remote Lifecycle Listener. The code to perform this little magic can be found at org.apache.catalina.mbeans.JmxRemoteLifecycleListener.
令人遗憾的是,无法指定临时端口将分配到何处——它总是在启动时随机选择。这很可能意味着您的防火墙需要成为该死的瑞士奶酪!但是,有解决方法。特别是,Apache Tomcat 通过其JMX 远程生命周期侦听器设置临时 JMX RMI 服务器端口。可以在org.apache.catalina.mbeans.JmxRemoteLifecycleListener找到执行这个小魔法的代码。
If you use this method, you might as well make sure that:
如果您使用此方法,您不妨确保:
- The JMX client has to authenticate to the JMX server
- The TCP exchange between the client and server is encrypted using SSL
- JMX 客户端必须向 JMX 服务器进行身份验证
- 客户端和服务器之间的 TCP 交换使用 SSL 加密
How that is done is described in the Sun/Oracle documentation
Sun/Oracle 文档中描述了如何完成
Other approaches
其他方法
You can do interesting permutations to avoid having to use the RMI protocol. In particular, you could add a servlet engine (like Jetty) to your process. Then add servlets that translate some HTTP-based exchange internally into direct accesses to the JVM's MBeanServer
. You would then be in 'case 0' but still have management capabilities, possibly through an HTML-based interface. The JBoss JMX Consoleis an example of this.
您可以进行有趣的排列以避免必须使用 RMI 协议。特别是,您可以将 servlet 引擎(如 Jetty)添加到您的流程中。然后添加 servlet,将一些基于 HTTP 的内部交换转换为对 JVM 的MBeanServer
. 然后,您将处于“案例 0”中,但仍具有管理功能,可能通过基于 HTML 的界面。在JBoss的JMX控制台是一个这样的例子。
More off-topic, you could use SNMP directly (something I haven't tried) according to this document.
更多题外话,你可以根据这个文档直接使用SNMP(我没有尝试过)。
Show and Tell Time
显示和讲述时间
And now it's time for some code to illustrate a JXM exchange. We take inspiration from a Sunoracle tutorial.
现在是时候用一些代码来说明 JXM 交换了。我们从Sunoracle 教程中获得灵感。
This runs on Unix. We use a JVM that is configured as a JMX server using:
这在 Unix 上运行。我们使用配置为 JMX 服务器的 JVM:
-Dcom.sun.management.jmxremote.port=9001
-Dcom.sun.management.jmxremote.port=9001
We use lsof
to check what TCP ports it is holding open:
我们lsof
用来检查它保持开放的 TCP 端口:
lsof -p <processid> -n | grep TCP
lsof -p <processid> -n | grep TCP
One should see something like this, the registry port and the ephemeral port:
人们应该看到这样的东西,注册端口和临时端口:
java 1068 user 127u IPv6 125614246 TCP *:36828 (LISTEN)
java 1068 user 130u IPv6 125614248 TCP *:9001 (LISTEN)
We use tcpdump
to inspect the packet exchange between JMX client and JMX server:
我们tcpdump
用来检查 JMX 客户端和 JMX 服务器之间的数据包交换:
tcpdump -l -XX port 36828 or port 9001
tcpdump -l -XX port 36828 or port 9001
We set up a file .java.policy
in the home directory to allow the client to actually connect remotely:
我们.java.policy
在home目录下设置一个文件,让客户端真正远程连接:
grant {
permission java.net.SocketPermission
"<JMX server IP address>:1024-65535", "connect,resolve";
};
And then we can run this and see what happens:
然后我们可以运行它,看看会发生什么:
package rmi;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.management.remote.rmi.RMIConnection;
import javax.management.remote.rmi.RMIServer;
public class Rmi {
public static void main(String args[]) throws Exception {
// We need a Security Manager (not necessarily an RMISecurityManager)
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
//
// Define a registry (this is just about building a local data structure)
//
final int comSunManagementJmxRemotePort = 9001;
Registry registry = LocateRegistry.getRegistry("<JMX server IP address>", comSunManagementJmxRemotePort);
//
// List registry entries. The client connects (using TCP) to the server on the
// 'com.sun.management.jmxremote.port' and queries data to fill the local registry structure.
// Among others, a definition for 'jmxrmi' is obtained.
//
System.out.print("Press enter to list registry entries");
System.in.read();
String[] names = registry.list();
for (String name : names) {
System.out.println("In the registry: " + name);
}
//
// 'Looking up' the entry registered under 'jmxrmi' involves opening and tearing down
// a TCP connection to the 'com.sun.management.jmxremote.port', as well as a TCP
// connection to an ephemeral secondary port chosen at server startup.
// The actual object locally obtained is a "javax.management.remote.rmi.RMIServerImpl_Stub"
// indicating where the ephemeral port is.
// "RMIServerImpl_Stub[UnicastRef [liveRef: [endpoint:[$IP:$EPHEMERAL_PORT](remote),objID:[-62fb4c1c:131a8c709f4:-7fff, -3335792051140327600]]]]"
//
System.out.print("Press enter to get the 'jmxrmi' stub");
System.in.read();
RMIServer jmxrmiServer = (RMIServer)registry.lookup("jmxrmi");
System.out.println(jmxrmiServer.toString());
//
// Now get a "RMI Connection" to the remote. This involves setting up and tearing
// down a TCP connection to the ephemeral port.
//
System.out.print("Press enter to get the 'RMIConnection'");
System.in.read();
RMIConnection rcon = jmxrmiServer.newClient(null);
//
// Ask away. This involves setting up and tearing
// down a TCP connection to the ephemeral port.
//
System.out.print("Press enter to get the 'domains'");
System.in.read();
for (String domain : rcon.getDomains(null)) {
System.out.println("Domain: " + domain);
}
//
// Ok, that will do. For serious applications, we better use the higher-level JMX classes
//
}
}
回答by Ivan Koblik
Actually there is an undocumented property that you can use to force JMX create remotely accessible connectors on random port numbers.
实际上,有一个未公开的属性可用于强制 JMX 在随机端口号上创建可远程访问的连接器。
-Dcom.sun.management.jmxremote.authenticate="false"
-Dcom.sun.management.jmxremote="true"
-Dcom.sun.management.jmxremote.ssl="false"
-Dcom.sun.management.jmxremote.port="0"
-Dcom.sun.management.jmxremote.local.only="false"
Last two properties are of most importance.
最后两个属性是最重要的。
回答by Guy Hillyer
I've been working recently to figure out how to enable remote JMX management from java code, without requiring the JVM to have been started with special properties set. The solution I settled on is to start my own private RMI registry -- easy enough -- and to expose the JMX service on that registry. I create my own MBeanServer, then create a new JMXConnectorServer. The JMXConnectorServer is created through a call like
我最近一直在研究如何从 Java 代码启用远程 JMX 管理,而无需使用特殊属性集启动 JVM。我确定的解决方案是启动我自己的私有 RMI 注册中心——这很容易——并在该注册中心公开 JMX 服务。我创建了自己的 MBeanServer,然后创建了一个新的 JMXConnectorServer。JMXConnectorServer 是通过像这样的调用创建的
connector = JXMConnectorServerFactory.newJMXConnectorServer(url, null, server);
Where server is the MBeanServer, and url is an instance of JMXServiceURL.
其中 server 是 MBeanServer,url 是 JMXServiceURL 的一个实例。
The url is of the form "service:jmx:rmi:///jndi/rmi://localhost:/jmxrmi" where port is the (local) private registry's port number. "jmxrmi" is the standard service name for the JMX service.
url 的格式为“service:jmx:rmi:///jndi/rmi://localhost:/jmxrmi”,其中 port 是(本地)私有注册中心的端口号。“jmxrmi”是 JMX 服务的标准服务名称。
After setting this up, and starting the connector, I find that I can connect to it from jconsole using hostname:port.
设置完并启动连接器后,我发现我可以使用主机名:端口从 jconsole 连接到它。
This entirely addresses my needs; I will be interested to know if anyone sees a flaw in this approach.
这完全满足了我的需求;我很想知道是否有人看到了这种方法的缺陷。
Reference: JMX Tutorial, Chap. 3
回答by Yu Chen
If you happen to run your application inside Glassfish app server, simply run the following asadmin command, you would need to restart all running servers for the change to take affect.
如果您碰巧在 Glassfish 应用服务器中运行您的应用程序,只需运行以下 asadmin 命令,您需要重新启动所有正在运行的服务器以使更改生效。
./asadmin enable-secure-admin
./asadmin enable-secure-admin
There are extra Glassfish server configurations to further enable security, see more at Connecting remotely to Glassfish through JMX.
有额外的 Glassfish 服务器配置可以进一步启用安全性,请参阅通过 JMX 远程连接到 Glassfish 中的更多信息。