|
|
Huh? What?
An E-playground for members of Bebear.net
Subscribe
Receive the RSS Feed of Samsara updates.
Links
People's pages that live on this server
Al Hoang
Al Crockett
Citizens For a Clean Environment
Andy Chen
Dave Phillips
Peter Tanski
Dan
Jon Constant
Kiwa Sasaki
A Musing Fool
Paul Lavoie
Ken Watanabe
Stephen Young
|
|
|
No comment
[/al]
permanent link
So I read some articles (
[1],
[2],
[3])
on a really nice piece of technology called
Java Management Extensions (JMX)
that allows you to:
- Watch memory usage of a Java JVM in real time
- Allows this to be done remotely as well as locally
- Offers a very nice GUI called JConsole
- Allows you run the garabage collector on the Java VM (I think) in order to try to reclaim unused memory
After reading this I was convinced it was the greatest thing since sliced
bread and started enabling it. My first shot at following the instructions
above was a failure. I didn't connect to anything. After some network
tracing and head scritching I googled around and found people also had
similar issues (
[4],
[5],
[6],
[7],
[8] ). The problem revolves around the fact that JMX relies on some older
Java technology called RMI.
RMI by default uses a model that is very similar to Sun's RPC mechanism
which means it uses dynamic ports to be able to communicate between a
client and a server. Dynamic ports is a big problem when you have a
firewall configured on your host. So all the instructions in
[1],
[2], and
[3]
are completely useless if you have a firewalled configuration. The
port setting that you are giving in those instructions is merely for
a serviced called the RMI registry whose main job is to listen for connections
then tell the client to connect to some dynamically assigned port on the
server.
However it IS possible to write some Java glue code to statically assign
a listening port for the RMI server. This is documented in
[5],
[6], and
[7]
however I found the documentation a little bit lacking if you don't really
know web programming in Java really well. For example where do you put the
code snippets? Why are they using a static method if it's going into
a servlet? (As far as I know you should put it in init() and NOT make it
static if you want to follow the Servlet API)
Where do you drop this into Tomcat? Do I need to configure one of those
aggravating
XML config files?
So, here is my (sorta) step-by-step process for enabling JMX on Tomcat
with a firewall for those of us who aren't Java experts but can read
a little bit on Java Servlet Programming to figure out how to make a
simple webapp:
- Decide on 2 ports to open up on your firewall.
I chose 9999 and 3000.
9999 is my RMI Registry listener and 3000 is where the RMI server is
- Create a servlet that you will copy as a webapp into your Tomcat directory.
For my webapp, I call it JMXPortServer
- You can use servlet code like the following (Stolen MOSTLY from the links
- I created a file called JMXPortServer.java for the object JMXPortServer.
This file will go into $WEBAPP_HOME/WEB-INF/classes/ when it's compiled.
Here is what went into my JMXPortServer (It's basically stolen from the
links above with some changes to follow the Java Servlet API.
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class JMXPortServer extends HttpServlet {
private static final long serialVersionUID = 1L;
static JMXConnectorServer cs;
static String jmxHost;
public void init() throws ServletException {
try {
// Start rmi registry
System.out.println("Create the RMI registry on port 9999");
LocateRegistry.createRegistry(9999);
// Instantiate the MBean server
System.out.println("Get the platform's MBean server");
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// Environment map
System.out.println("Initialize the environment map");
HashMap env = new HashMap();
// Create an RMI connector server
System.out.println("Create an RMI connector server");
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi://localhost:3000/jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs);
// Start the RMI connector server
System.out.println("Start the RMI connector server");
cs.start();
} catch (Exception ex) {
System.err.println(ex);
}
}
}
- Create a web.xml that will go in $WEBAPP_HOME/WEB-INF/web.xml.
Click Here to
download a suitable web.xml file (
Viewing XML in HTML is a pain)
- In your web.xml file you need to be sure you have an XML tag with load-on-startup.
This will ensure that this servlet is loaded when Tomcat starts up
rather than when Tomcat feels it is appropriate. (I got bit by this one)
- Now you should be able to make a warfile from the pieces shown above and
drop this into Tomcat.
- I think you need to also set
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false in your JAVA_OPTS (JVM Options)
(For Tomcat look in $CATALINA_HOME/bin/setenv.sh for a good place to
set this)
- This warfile you can now just drop into Tomcat and it will always start up the JMX Console so you can monitor things
- To connect with JConsole you'll need to enter the following URL
service:jmx:rmi://myserver:3000/jndi/rmi://myserver:9999/server.
Make sure to substitute the name or IP address of your server with
myserver
Caveats
- I've done nothing about security here. From here on you're on your own
- The code is REALLY ugly (I could fix a lot) but I know it works
- I could be doing something wrong but since I'm not a Java ninja... oh well.. someone can email me and point it out
References
AMIS: Modify Spring Beans and log4j levels via JMX
O'Reilly: Monitoring Local & Remote Apps using JMX
JBoss: Using Jconsole
Penrose: Can't connect to a remote penrose server
Java Forums: Port redirection problems and RMI
Tomcat Bug 39055: Firewall access for JMX
JConsole through a firewall
JMX-RMI-SSL
[/al]
permanent link
|
|