Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><em>AFAIK,</em></p> <p>Here are the possibilites for connecting a <em>JMX client process</em> (a <strong>management application</strong> like jconsole, jmxterm, mc4j, jvmstat, jmxmonitor, jps, ...) to a <em>JMX server process</em> (the <strong>agent</strong>).</p> <p>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 <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/jmx/overview/connectors.html#wp5529" rel="noreferrer">other protocols</a>, in particular 'RMI-IIOP' and 'JMXMP'. Special protocols are possible: the <a href="http://mx4j.sourceforge.net/" rel="noreferrer">MX4J</a> project for example additionally provides SOAP/HTTP and various serialization protocols over HTTP. </p> <p>Refer to <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html" rel="noreferrer">Sun/Oracle docs</a> for details on configuration.</p> <p>Also have a look at the file <code>jre/lib/management/management.properties</code> in your JDK distribution.</p> <p>So, the possibilities:</p> <p><strong>Case 0: The JVM is started without any particular configuration</strong></p> <p>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 <a href="http://docs.oracle.com/javase/6/docs/api/javax/management/MBeanServer.html" rel="noreferrer">MBeanServer</a> programmatically 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.</p> <p>Since Java 6: Even if not explicitely configured, one can access JMX functionality of the JVM <em>locally</em> (from the same machine) as described in "Case 1".</p> <p><strong>Case 1: The JVM is started with <code>-Dcom.sun.management.jmxremote</code></strong> </p> <p>The JVM is configured to work as a <em>local</em> (same-machine-only) JMX server.</p> <p>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 <code>/tmp/hsperfdata_[user]</code>. This is alluded to in the Sun documentation and called "local monitoring" (and also the <a href="http://docs.oracle.com/javase/6/docs/jdk/api/attach/spec/index.html" rel="noreferrer">Attach API</a>). It does not work on FAT filesystems as permissions cannot be set correctly there. See <a href="https://blogs.oracle.com/lmalventosa/entry/jconsole_local_process_list_on" rel="noreferrer">this blog entry</a>.</p> <p>Sun recommends running <code>jconsole</code> on a machine separate from the JMX server as <code>jconsole</code> apparently is a resource hog, so this "local monitoring" thing is not necessarily a good idea.</p> <p>Local monitoring is, however, rather secure, only being usable locally and being easily controlled through filesystem permissions.</p> <p><strong>Case 2: The JMX server is started with <code>-Dcom.sun.management.jmxremote.port=[rmiregistryport]</code></strong> </p> <p>The JVM is configured to work as a JMX server listening on several TCP ports.</p> <p>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.</p> <p>Local as described in 'Case 1' is always enabled in 'Case 2'.</p> <p>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. </p> <p><em>This implies that you have to look at the security implications</em>. You can make the JVM listen on 127.0.0.1:[rmiregistryport] only by setting <code>-Dcom.sun.management.jmxremote.local.only=true</code>.</p> <p>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 <a href="http://olegz.wordpress.com/2009/03/23/jmx-connectivity-through-the-firewall/" rel="noreferrer">workarounds</a>. In particular, Apache Tomcat sets the ephemeral JMX RMI server port via its <a href="http://tomcat.apache.org/tomcat-7.0-doc/config/listeners.html#Additional_Implementations" rel="noreferrer">JMX Remote Lifecycle Listener</a>. The code to perform this little magic can be found at <a href="http://grepcode.com/file/repo1.maven.org/maven2/org.apache.tomcat/tomcat-catalina-jmx-remote/7.0.14/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java/" rel="noreferrer">org.apache.catalina.mbeans.JmxRemoteLifecycleListener</a>.</p> <p>If you use this method, you might as well make sure that:</p> <ol> <li>The JMX client has to authenticate to the JMX server</li> <li>The TCP exchange between the client and server is encrypted using SSL</li> </ol> <p>How that is done is described in <a href="http://docs.oracle.com/javase/6/docs/technotes/guides/management/agent.html" rel="noreferrer">the Sun/Oracle documentation</a></p> <p><strong>Other approaches</strong></p> <p>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 <code>MBeanServer</code>. You would then be in 'case 0' but still have management capabilities, possibly through an HTML-based interface. The <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/management/SNMP.html" rel="noreferrer">JBoss JMX Console</a> is an example of this.</p> <p>More off-topic, you could use SNMP directly (something I haven't tried) according to <a href="http://docs.oracle.com/javase/1.5.0/docs/guide/management/SNMP.html" rel="noreferrer">this document</a>.</p> <p><strong>Show and Tell Time</strong> </p> <p>And now it's time for some code to illustrate a JXM exchange. We take inspiration from <a href="http://docs.oracle.com/javase/tutorial/rmi/client.html" rel="noreferrer">a Sunoracle tutorial</a>.</p> <p>This runs on Unix. We use a JVM that is configured as a JMX server using:</p> <p><code>-Dcom.sun.management.jmxremote.port=9001</code> </p> <p>We use <code>lsof</code> to check what TCP ports it is holding open:</p> <p><code>lsof -p &lt;processid&gt; -n | grep TCP</code></p> <p>One should see something like this, the registry port and the ephemeral port:</p> <pre><code>java 1068 user 127u IPv6 125614246 TCP *:36828 (LISTEN) java 1068 user 130u IPv6 125614248 TCP *:9001 (LISTEN) </code></pre> <p>We use <code>tcpdump</code> to inspect the packet exchange between JMX client and JMX server:</p> <p><code>tcpdump -l -XX port 36828 or port 9001</code></p> <p>We set up a file <code>.java.policy</code> in the home directory to allow the client to actually connect remotely:</p> <pre><code>grant { permission java.net.SocketPermission "&lt;JMX server IP address&gt;:1024-65535", "connect,resolve"; }; </code></pre> <p>And then we can run this and see what happens:</p> <pre><code>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("&lt;JMX server IP address&gt;", 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 // } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload