How to access Spring-boot JMX remotely

前端 未结 3 427
礼貌的吻别
礼貌的吻别 2020-11-30 23:00

I know that spring automatically expose JMX beans. I was able to access it locally using VisualVM.

However on prod how I can connect to remotely to the app using it\

相关标签:
3条回答
  • 2020-11-30 23:29

    Add the following JVM Properties in "$JAVA_OPTS" (in your application):

    -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:

    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.

    0 讨论(0)
  • 2020-11-30 23:43

    A tested approach on Java 1.8.0_71 and Spring Boot(1.3.3.RELEASE). Append below parameters to JVM arguments for monitored 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.

    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.

    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.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.

    0 讨论(0)
  • 2020-11-30 23:52

    By default JMX is automatically accessible locally, so running jconsole locally would detect all your local java apps without port exposure.

    To access an app via JMX remotely you have to specify an RMI Registry port. 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. ("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 options:

    Option 1: Command line

    -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.

    Option 2: Tomcat/Tomee configuration

    Configure a JmxRemoteLifecycleListener:

    Maven Jar:

        <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:

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

    Option 3: configure programmatically

    @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. If you specify both, you won't get the random high "problem".

    0 讨论(0)
提交回复
热议问题