Skip to main content

TOTD #62: How to remotely manage/monitor your Rails/Merb applications on JRuby/GlassFish using JMX API ?

Posted by arungupta on January 8, 2009 at 10:21 AM PST



TOTD
#61
showed how to manage/monitor a Rails/Merb application
running using JRuby/GlassFish using standard Java tools. Both the
application and the management tools are running on the same machine.
But that's never the case in a production environment. Instead remote
management of an application is required when running in production
mode. Fortunately, similar set of tools can be used for remote
management as well.



However the underlying Java Virtual Machine needs to be configured to
enable remote monitoring. This is achieved by setting JAVA_OPTS
environment variables as shown below:



Set up the following envinronment variable before running the
Rails/Merb application:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
export JAVA_OPTS="-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8686
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false"



The first property enables the JMX remote agent (aka MBeans server) and
local monitoring. The second property configures the port number for
remote management using JMX/RMI connections. The third and fourth
properties, for simplicity only, disable access control and SSL for
remote monitoring. It is highly recommended to use them in a
production environment. href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#auth">Using
Password Authentication provide more details about
configuring passwords for access control. href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#SSL_enabled">Using
SSL provide more details about configuring SSL.



Now for a Rails/Merb application running on GlassFish all the MBeans
are also available on the JMX agent running on port 8686. This agent
can be accessed using the href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#connecting">standard
URL as shown below:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
service:jmx:rmi:///jndi/rmi://192.168.124.1:8686/jmxrmi



"192.168.124.1" is the host's IP address on which the Rails/Merb
application is running and "8686" is the port configured in JAVA_OPTS.
More details about the URL are available href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#connecting">here.



First, lets use jconsole on a different machine to monitor this
application. Start jconsole by typing the command in a shell as:


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
jconsole



In the "New Connection" window, select "Remote Process" and enter the
URL defined above as shown
below:



src="http://blogs.sun.com/arungupta/resource/images/jconsole-rails-monit-remote-connection.png">



And then the management data snapshot is captured as shown below:



href="http://blogs.sun.com/arungupta/resource/images/jconsole-rails-monit-remote-overview.png"> style="border: 0px solid ; width: 700px; height: 511px;" alt=""
src="http://blogs.sun.com/arungupta/resource/images/jconsole-rails-monit-remote-overview.png">



And here is a snapshot from a remote Solaris machine:



href="http://blogs.sun.com/arungupta/resource/ror/jconsole-rails-monit-remote-overview-solx86.png"> style="border: 0px solid ; width: 700px; height: 536px;" alt=""
src="http://blogs.sun.com/arungupta/resource/ror/jconsole-rails-monit-remote-overview-solx86.png">



Notice the URL, as opposed to "pid", is shown on the jconsole window.
This indicates that remote connection is being used instead of local
process id. href="http://blogs.sun.com/arungupta/entry/totd_61_how_to_locally">TOTD
#61 further explains how jconsole can be used to
manage/monitor your Rails/Merb applications.



As mentioned in href="http://blogs.sun.com/arungupta/entry/totd_61_how_to_locally">TOTD
#61, JRuby runtime exposes 4 different MBeans - ClassCache,
Config, JITCompiler and ParserStats - all in "org.jruby" domain. Lets
write a client application that query these MBeans to monitor the state
of JRuby runtime and perform some management actions based upon the
returned results.



Here is the Ruby client code using href="http://java.sun.com/javase/technologies/core/mntr-mgmt/javamanagement/">Java
Management Extensions (JMX) APIs. 


style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
cellpadding="2" cellspacing="2">
include Java



import java.io.IOException

import java.util.HashSet

import java.util.Set

import javax.management.JMRuntimeException

import javax.management.MBeanServerConnection

import javax.management.MalformedObjectNameException

import javax.management.ObjectName

import javax.management.JMX

import javax.management.remote.JMXConnector

import javax.management.remote.JMXConnectorFactory

import javax.management.remote.JMXServiceURL

import org.jruby.management.ClassCacheMBean

import org.jruby.management.ConfigMBean



url = JMXServiceURL.new
"service:jmx:rmi:///jndi/rmi://192.168.124.1:8686/jmxrmi"

mbsc = JMXConnectorFactory.connect(url, nil).get_mbean_server_connection



names = HashSet.new(mbsc.query_names(ObjectName.new("org.jruby:*"),
nil))

names.each { |name|

     service =
name.get_key_property "service"

     if service == "ClassCache"

          
@cc_mbean = JMX.new_mbean_proxy(mbsc, name,
Java::org.jruby.management.ClassCacheMBean.java_class)

     elsif service == "Config"

          
@c_mbean = JMX.newMBeanProxy(mbsc, name,
Java::org.jruby.management.ConfigMBean.java_class)

     end

}



# clear the cache if it's full

if @cc_mbean.is_full

    puts @c_mbean.get_jit_max

    puts @c_mbean.get_jit_threshold

    puts @cc_mbean.get_class_load_count

    @cc_mbean.flush

else

    puts "Class Cache is not full"

    printf "Loaded: %d, Reused: %d, Live:
%d\n", @cc_mbean.get_class_load_count,

     
@cc_mbean.get_class_reuse_count, @cc_mbean.get_live_class_count

end



Here are the main tasks achieved by this code:

  • Do include/import for Java classes
  • Connect with the JMX Agent where JRuby MBeans are
    registered and obtain a MBean Server Connection (explained href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#connecting">here)
  • Query for all the MBeans in "org.jruby" domain
  • Create proxies for ClassCache and Config MBeans
  • Flush the ClassCache if its full and print some debugging
    information

These MBeans are part of JRuby runtime so provide relevant
management/montoring
information corresponding to that. But as you can see it's fairly
trivial to write a client to query MBeans and achieve dynamism using
standard Ruby code.



Each JRuby-exposed MBean has multiple attributes
that can be utilized to monitor your application and take appropriate
actions. For example, an application could href="http://java.sun.com/j2se/1.5.0/docs/guide/management/mxbeans.html#low_memory">detect
low memory and stop accepting new connections.



And you can continue to use GlassFish

for running your Rails and Merb applications ( href="http://blogs.sun.com/Jacobkessler/entry/custom_launch_scripts_for_real">now
Sinatra as well)!



Subsequent blogs in this series will discuss:

  • How to
    remotely manage your Rails/Merb applications using
    JMX API ?
  • How to publish your own metrics that can be managed using
    JMX API ?
  • How to use jmx gem to manage/monitor ?
  • How to use VisualVM to get more information about the
    underlying VM ?
  • How to use NewRelic/FiveRuns to manage/monitor an
    application ?

Please leave suggestions on other TOTD (Tip Of The Day) that
you'd like to see.
A complete archive of all tips is available href="http://blogs.sun.com/arungupta/tags/totd">here.




Technorati: totd
glassfish
jruby href="http://technorati.com/tag/rubyonrails">rubyonrails
merb href="http://technorati.com/tag/jmx">jmx
manage
monitor

Related Topics >>