当前位置:  开发笔记 > 编程语言 > 正文

Java 6是否为JMX远程连接打开了默认端口?

如何解决《Java6是否为JMX远程连接打开了默认端口?》经验,为你挑选了3个好方法。

我的具体问题与JDK 1.6中使用的JMX有关:如果我使用JRE 1.6运行Java进程

com.sun.management.jmxremote

在命令行中,Java是否为远程JMX连接选择了一个默认端口?

背景故事:我目前正在尝试开发一个程序,让客户能够通过JMX从远程机器连接到我们的一个进程.目标是实现对实时显示控制台上发生的情况的远程调试.由于他们的服务级别协议,他们强烈有动力捕获尽可能多的数据,如果情况看起来太复杂,无法快速修复,重新启动显示控制台并允许它重新连接到服务器端.

我知道我可以在JDK 1.6进程上运行jconsole,在JDK 1.6.7进程上运行jvisualvm,同时可以访问控制台.但是,由于操作要求和涉及的人员问题,我们强烈要求远程获取我们需要的数据并重新启动和运行.

编辑:我知道命令行端口属性

com.sun.management.jmxremote.port=portNum

我想回答的问题是,如果你没有在命令行设置该属性,Java是否会选择另一个端口进行远程监控?如果是这样,你怎么能确定它可能是什么?



1> David Tonhof..:

据我所知,

以下是将JMX客户端进程(jconsole,jmxterm,mc4j,jvmstat,jmxmonitor,jps等管理应用程序)连接到JMX服务器进程(代理)的可能性.

连接JMX客户端和JMX服务器的协议被假定为"Java RMI"(又名"RMI-JRMP").这应该是默认值.可以配置其他协议,特别是"RMI-IIOP"和"JMXMP".特殊协议是可能的:例如,MX4J项目还通过HTTP提供SOAP/HTTP和各种序列化协议.

有关配置的详细信息,请参阅Sun/Oracle文档.

jre/lib/management/management.properties请查看JDK发行版中的文件.

所以,可能性:

案例0:JVM在没有任何特定配置的情况下启动

在Java 6之前:JVM不像JMX服务器那样运行.在JVM中运行的任何程序都可以以编程方式访问JVM的MBeanServer,并使用它在线程之间进行有趣的数据交换或进行JVM监视,但不能从JVM进程外部进行管理.

从Java 6开始:即使没有明确配置,也可以在本地(从同一台机器)访问JVM的JMX功能,如"案例1"中所述.

案例1:JVM以启动 -Dcom.sun.management.jmxremote

JVM配置为作为本地(仅限同一台计算机)的JMX服务器.

在这种情况下(原则上仅适用于Sun/Oracle JVM),JMX客户端可以通过中找到的内存映射文件连接到JMX服务器/tmp/hsperfdata_[user].这在Sun文档中提到并称为"本地监视"(以及Attach API).它不适用于FAT文件系统,因为无法在那里正确设置权限.请参阅此博客条目.

Sun建议jconsole在与JMX服务器分开的机器上运行,因为这jconsole显然是一种资源匮乏,因此这种"本地监控"事情不一定是个好主意.

但是,本地监控相当安全,只能在本地使用,并且可以通过文件系统权限轻松控制.

案例2:启动JMX服务器 -Dcom.sun.management.jmxremote.port=[rmiregistryport]

JVM配置为在多个TCP端口上侦听JMX服务器.

命令行上指定的端口将由JVM分配,并且RMI注册表将在那里可用.注册表通告名为"jmxrmi"的连接器.它指向第二个随机分配的TCP端口(一个"短暂"端口),JMX RMI服务器在该端口上进行侦听,并通过该端口进行实际的数据交换.

"情况1"中描述的本地始终在"情况2"中启用.

默认情况下,JMX服务器侦听所有接口,因此您可以通过本地连接到127.0.0.1:[rmiregistryport]连接到它(并控制它),也可以通过远程连接到[任何外部IP地址]:远程连接[某些端口] .

这意味着您必须考虑安全隐患.您只能通过设置使JVM侦听127.0.0.1:[rmiregistryport] -Dcom.sun.management.jmxremote.local.only=true.

非常不幸的是,人们无法指定临时端口的分配位置 - 它总是在启动时随机选择.这可能意味着您的防火墙需要成为该死的瑞士奶酪!但是,有一些解决方法.特别是,Apache Tomcat通过其JMX远程生命周期监听器设置短暂的JMX RMI服务器端口.可以在org.apache.catalina.mbeans.JmxRemoteLifecycleListener中找到执行这个小魔术的代码.

如果您使用此方法,您还可以确保:

    JMX客户端必须向JMX服务器进行身份验证

    客户端和服务器之间的TCP交换使用SSL加密

Sun/Oracle文档中描述了如何完成此操作

其他方法

您可以进行有趣的排列,以避免使用RMI协议.特别是,您可以向进程添加servlet引擎(如Jetty).然后添加servlet,将内部基于HTTP的交换转换为对JVM的直接访问MBeanServer.然后,您将处于'case 0'但仍具有管理功能,可能通过基于HTML的界面.在JBoss的JMX控制台是一个这样的例子.

根据本文档,您可以直接使用SNMP(我没有尝试过).

显示和告诉时间

现在是一些代码来说明JXM交换的时候了.我们从Sunoracle教程中获取灵感.

这在Unix上运行.我们使用配置为JMX服务器的JVM,使用:

-Dcom.sun.management.jmxremote.port=9001

我们用它lsof来检查它保持打开的TCP端口:

lsof -p -n | grep TCP

人们应该看到这样的东西,注册表端口和短暂的端口:

java    1068 user  127u  IPv6 125614246                 TCP *:36828 (LISTEN)
java    1068 user  130u  IPv6 125614248                 TCP *:9001  (LISTEN)

我们tcpdump用来检查JMX客户端和JMX服务器之间的数据包交换:

tcpdump -l -XX port 36828 or port 9001

我们.java.policy在主目录中设置了一个文件,允许客户端实际远程连接:

grant {
    permission java.net.SocketPermission 
    ":1024-65535", "connect,resolve";
};

然后我们可以运行它,看看会发生什么:

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("", 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
        //
    }   
}



2> Eddie..:

该文件表明,JMX代理使用本地港口-这是从无法访问外机-除非您指定以下属性:

com.sun.management.jmxremote.port=portNum

这是出于安全原因,也是出于Potato Head先生的原因.因此,看起来Java 6没有为JMX 打开默认的远程可访问端口.

编辑:在OP添加了更多信息的答案后添加.

您拥有的另一个选项是以某种方式创建一个本地代理,该代理侦听所有本地JMX连接并导出此信息.这样,您就不需要在服务器上对每个JVM实例进行这种神奇的配置.相反,本地代理可以通过JMX连接到所有JVM,然后以某种方式远程公开这些信息.我并不确切地知道如何实现这一点,但是这样的事情可能比通过JMX远程公开所有JVM所做的工作要少.



3> Ivan Koblik..:

实际上,有一个未记录的属性可用于强制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"

最后两个属性是最重要的.

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有