如何远程访问Spring-boot JMX

问题描述 投票:0回答:4

我知道 spring 自动公开 JMX beans。我能够使用 VisualVM 在本地访问它。

但是在产品上我如何使用它的 JMX beans 远程连接到应用程序?是否有默认端口或者我应该另外定义什么?

谢谢, 雷.

spring spring-boot jmx
4个回答
58
投票

默认情况下,JMX 可在本地自动访问,因此运行

jconsole
locally 将检测所有本地 Java 应用程序,而无需暴露端口。

要通过 JMX 远程访问应用程序,您必须指定 RMI 注册表端口。要知道的是,连接时,JMX 在该端口上初始化,然后然后随机高端口上建立数据连接,如果中间有防火墙,这将是一个巨大的问题。 (“嘿,系统管理员,打开所有内容,好吗?”)。

要强制 JMX 连接回您已建立的同一端口,您有以下几个选项。注意:您可以为 JMX 和 RMI 使用不同的端口,也可以使用相同的端口。

选项 1:命令行

-Dcom.sun.management.jmxremote.port=$JMX_REGISTRY_PORT 
-Dcom.sun.management.jmxremote.rmi.port=$RMI_SERVER_PORT

如果您使用 Spring Boot,您可以将其放入与

(appname).conf
部署一起存在的
(appname).jar
文件中。

选项2:Tomcat/Tomee配置

配置一个JmxRemoteLifecycleListener

Maven 罐子:

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina-jmx-remote</artifactId>
        <version>8.5.9</version>
        <type>jar</type>
    </dependency>

配置您的server.xml:

<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
      rmiRegistryPortPlatform="10001" rmiServerPortPlatform="10002" />

选项 3:以编程方式配置

@Configuration
public class ConfigureRMI {

    @Value("${jmx.rmi.host:localhost}")
    private String rmiHost;

    @Value("${jmx.rmi.port:1099}")
    private Integer rmiPort;

    @Bean
    public RmiRegistryFactoryBean rmiRegistry() {
        final RmiRegistryFactoryBean rmiRegistryFactoryBean = new RmiRegistryFactoryBean();
        rmiRegistryFactoryBean.setPort(rmiPort);
        rmiRegistryFactoryBean.setAlwaysCreate(true);
        return rmiRegistryFactoryBean;
    }

    @Bean
    @DependsOn("rmiRegistry")
    public ConnectorServerFactoryBean connectorServerFactoryBean() throws Exception {
        final ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
        connectorServerFactoryBean.setObjectName("connector:name=rmi");
        connectorServerFactoryBean.setServiceUrl(String.format("service:jmx:rmi://%s:%s/jndi/rmi://%s:%s/jmxrmi", rmiHost, rmiPort, rmiHost, rmiPort));
        return connectorServerFactoryBean;
    }
}

您将看到,技巧是

serviceUrl
,您可以在其中指定 jmx:rmi 主机/端口和 jndi:rmi 主机/端口。如果您同时指定两者,您将不会遇到随机高“问题”。

编辑: 为了使 JMX 远程处理正常工作,您需要做出有关身份验证的决定。最好分 3 个不同的步骤来完成:

  1. 基本设置
    -Dcom.sun.management.jmxremote.authenticate=false
    然后
  2. 添加一个 密码文件 (
    -Dcom.sun.management.jmxremote.password.file
    )。 见 此处获取说明。 +
    -Dcom.sun.management.jmxremote.ssl=false
    然后
  3. 设置 SSL。

40
投票

在“$JAVA_OPTS”(在您的应用程序中)中添加以下 JVM 属性:

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=<PORT_NUMBER> -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=<HOST'S_IP>

在 Jconsole/Visual VM 中使用以下命令进行连接:

service:jmx:rmi:///jndi/rmi://<HOST'S_IP>:<PORT_NUMBER>/jmxrmi

它不会启用安全性,但会帮助您连接到远程服务器。


6
投票

在 Java 1.8.0_71 和 Spring Boot(1.3.3.RELEASE) 上经过测试的方法。 将以下参数附加到受监控 JVM 的 JVM 参数。

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=12348 -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.rmi.port=12349 -Dcom.sun.management.jmxremote.password.file=/somewhere/jmxremote.password -Dcom.sun.management.jmxremote.access.file=/somewhere/jmx/jmxremote.access

com.sun.management.jmxremote.port
用于定义固定RMI注册表端口,
com.sun.management.jmxremote.rmi.port
用于指示JVM使用固定RMI端口,但不使用随机端口。

通过设置此选项,我可以通过仅打开 12348 和 12349 端口的防火墙将 JVM 客户端从远程主机连接到受监控的 JVM。

我在远程计算机上使用

java -jar cmdline-jmxclient-0.10.3.jar user:pwd hostip:12348
进行了测试,它生成以下输出(仅为了演示而缩短)。

java.lang:type=Runtime
java.lang:name=PS Scavenge,type=GarbageCollector
Tomcat:J2EEApplication=none,J2EEServer=none,WebModule=//localhost/,j2eeType=Filter,name=requestContextFilter
java.nio:name=mapped,type=BufferPool
Tomcat:host=localhost,type=Host
java.lang:name=Compressed Class Space,type=MemoryPool
.......

jar 是从这里下载的。


0
投票

另一种选择

jmxremote.password 和 jmxremote.access 文件参考

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.jmx.support.ConnectorServerFactoryBean;
import org.springframework.remoting.rmi.RmiRegistryFactoryBean;

@Configuration
public class ConfigureRMI {

    @Value("${jmx.rmi.password.file:/tmp/jmxremote.password}")
    private String passwordFile;

    @Value("${jmx.rmi.access.file:/tmp/jmxremote.access}")
    private String accessFile;

    @Value("${jmx.rmi.port:19999}")
    private Integer rmiPort;

    @Bean
    public RmiRegistryFactoryBean rmiRegistry() {
        final RmiRegistryFactoryBean rmiRegistryFactoryBean = new RmiRegistryFactoryBean();
        rmiRegistryFactoryBean.setPort(rmiPort);
        rmiRegistryFactoryBean.setAlwaysCreate(true);
        return rmiRegistryFactoryBean;
    }

    @Bean
    @DependsOn("rmiRegistry")
    public ConnectorServerFactoryBean connectorServerFactoryBean() throws Exception {
        final ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
        connectorServerFactoryBean.setObjectName("connector:name=rmi");
        Map<String, Object> properties = new HashMap<>();
        properties.put("jmx.remote.x.password.file", passwordFile);
        properties.put("jmx.remote.x.access.file", accessFile);
        connectorServerFactoryBean.setEnvironmentMap(properties);
        connectorServerFactoryBean.setServiceUrl(String.format("service:jmx:rmi:///jndi/rmi://:%s/jmxrmi", rmiPort));
        return connectorServerFactoryBean;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.