简体   繁体   English

"如何远程访问 Spring-boot JMX"

[英]How to access Spring-boot JMX remotely

I know that spring automatically expose JMX beans.我知道spring会自动公开JMX bean。 I was able to access it locally using VisualVM.我能够使用 VisualVM 在本地访问它。

However on prod how I can connect to remotely to the app using it's JMX beans?但是在产品上,我如何使用它的 JMX bean 远程连接到应用程序? Is there a default port or should I define anything in addition?是否有默认端口或者我应该另外定义任何东西?

Thanks, ray.谢谢,雷。

"

By default JMX is automatically accessible locally, so running jconsole locally would detect all your local java apps without port exposure.默认情况下,JMX 可在本地自动访问,因此在本地运行jconsole将检测所有本地 Java 应用程序,而不会暴露端口。

To access an app via JMX remotely you have to specify an RMI Registry port.要通过 JMX远程访问应用程序,您必须指定一个 RMI 注册表端口。 The thing to know is that when connecting, JMX initializes on that port and then establishes a data connection back on a random high port, which is a huge problem if you have a firewall in the middle.要知道的是,在连接时,JMX 在该端口上初始化,然后随机的高端口上建立数据连接,如果中间有防火墙,这是一个大问题。 ("Hey sysadmins, just open up everything, mkay?"). (“嘿系统管理员,打开所有东西,好吗?”)。

To force JMX to connect back on the same port as you've established, you have a couple of the following options.要强制 JMX 连接回与您建立的相同的端口,您有以下几个选项。 Note: you can use different ports for JMX and RMI or you can use the same port.注意:您可以为 JMX 和 RMI 使用不同的端口,也可以使用相同的端口。

Option 1: Command line选项 1:命令行

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

If you're using Spring Boot you can put this in your (appname).conf file that lives alongside your (appname).jar deployment.如果你使用 Spring Boot,你可以把它放在你的(appname).conf文件中,该文件与你的(appname).jar部署一起存在。

Option 2: Tomcat/Tomee configuration选项 2:Tomcat/Tomee 配置

Configure a JmxRemoteLifecycleListener :配置一个JmxRemoteLifecycleListener

Maven Jar: Maven 罐子:

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

Configure your server.xml:配置你的 server.xml:

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

Option 3: configure programmatically选项 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;
    }
}

The trick, you'll see, is the serviceUrl in which you specify both the jmx:rmi host/port and the jndi:rmi host/port.您将看到,诀窍是在serviceUrl中指定 jmx:rmi 主机/端口和 jndi:rmi 主机/端口。 If you specify both, you won't get the random high "problem".如果您同时指定两者,您将不会遇到随机高“问题”。

Edit: For JMX remoting to work, you'll need to make a decision about authenticating.编辑:要使 JMX 远程处理工作,您需要做出有关身份验证的决定。 It's better to do it in 3 distinct steps: 1) basic setup with -Dcom.sun.management.jmxremote.authenticate=false then 2) add a password file ( -Dcom.sun.management.jmxremote.password.file ).最好分 3 个不同的步骤进行:1) 使用-Dcom.sun.management.jmxremote.authenticate=false进行基本设置,然后 2) 添加密码文件 ( -Dcom.sun.management.jmxremote.password.file )。 See here for instructions. 有关说明,请参见此处。 + -Dcom.sun.management.jmxremote.ssl=false and then 3) set up SSL. + -Dcom.sun.management.jmxremote.ssl=false然后 3) 设置 SSL。

Add the following JVM Properties in "$JAVA_OPTS" (in your application):在“$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>

In the Jconsole/Visual VM use the following to connect:在 Jconsole/Visual VM 中,使用以下命令进行连接:

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

It doesn't enable security, but will help you to connect to the remote server.它不会启用安全性,但会帮助您连接到远程服务器。

A tested approach on Java 1.8.0_71 and Spring Boot(1.3.3.RELEASE).在 Java 1.8.0_71 和 Spring Boot(1.3.3.RELEASE) 上经过测试的方法。 Append below parameters to JVM arguments for monitored JVM.将以下参数附加到受监控 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

The com.sun.management.jmxremote.port is used to define the fixed RMI registry port, and the com.sun.management.jmxremote.rmi.port is used to instruct JVM to use fixed RMI port, but NOT use random one. com.sun.management.jmxremote.port用于定义固定 RMI 注册端口, com.sun.management.jmxremote.rmi.port用于指示 JVM 使用固定 RMI 端口,但不使用随机端口。

By setting this, I am able to connect JVM client from remote host to the monitored JVM via a firewall just opening 12348 and 12349 port.通过设置这一点,我可以通过防火墙将 JVM 客户端从远程主机连接到受监控的 JVM,只需打开 12348 和 12349 端口。

I tested using java -jar cmdline-jmxclient-0.10.3.jar user:pwd hostip:12348 on a remote machine, which generates below output(shortened just for demonstration).我在远程机器上使用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
.......

The jar is downloaded from Here .该 jar 是从这里下载的。

Another alternative另一种选择

Reference for jmxremote.password and jmxremote.access files<\/a> jmxremote.password 和 jmxremote.access 文件的参考<\/a>

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;
    }
}

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

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