Add Object Cache Monitoring Using JMX and Aspects

ike many companies, my company uses an object cache to store frequently accessed data in memory so the server doesn’t have to access the back-end database every time it handles a request for the same data. Caching provides advantages such as application performance improvement, scalability and minimizes the overhead required to acquire and release the objects.

In a recent project we needed to view and monitor the cache details (using a Web console) to study the data access trends for objects stored in the cache and determine which objects were better used by storing them in the cache instead of directly going to backend data store. We wanted to use the Java Management Extensions (JMX) technology for this requirement, but didn’t want to change any existing application code because we weren’t sure how much overhead the monitoring code would add. We decided to use Aspect Oriented Programming (AOP) techniques to dynamically introduce JMX code into existing Java classes and get the cache statistics that way. That way, if the monitoring overhead turned out to require too much overhead, we could easily unweave the JMX code from the application code, returning it to the exact state it was in prior to introducing the monitoring logic.

This article provides an overview of an Object Caching Monitor framework developed using JMX and AOP technologies. The article code uses Aspects to add monitoring capabilities (via JMX) into the Object Caching framework.

Why Monitor a Cache?
You can store any type of data in the cache, but the benefits increase when the data is accessed frequently and when it takes more time and resources to retrieve the data from the source, such as a database, than from the cache. When the cache is being used to store different types of data, cache monitoring becomes an important task from several different points of view, because you need to:

  • Know how objects in the cache get cleaned up on a regular interval.
  • Verify that objects stored in the cache are not taking too much memory?which could cause performance problems in the application.
  • Detect when the cache size grows beyond a maximum allowed threshold and raise any alerts to cleanup the cache.
What You Need
JBoss4, JBossCache, Eclipse, AJDT, and Ant

Monitoring in Java Enterprise Applications
Application monitoring and gathering statistics is an integral part of a Java enterprise application. These tasks should be given considerable importance right from the modeling and design phases of a project?not just tacked onto the implementation and post implementation phases. Developers should be involved in all the monitoring requirements of the application. Network administrators and operations groups should work collaboratively with the developers to understand the different parts of the application that will require monitoring when the application reaches a production environment. Application monitoring provides several benefits to all these IS groups. For example, developers can monitor the applications to explore any parts of the application that may need tuning and optimization, while the operations and network admin groups can use monitoring tools to detect O/S or server problems before they occur and to trigger warnings when server statistics such as CPU or memory usage approach the maximum allowed limits.

Many areas in a Java application and the application server can benefit from monitoring to create a scalable and highly available Java EE application. Table 1 shows some of the items that you should consider monitoring.

Table 1: The table shows some items that you should consider monitoring.

Category Monitoring Stats
System Monitoring OS Stats, CPU, Memory, I/O
Network Bandwidth, connection speed
Server Processor(s) details.
Application Server Cluster, JMS Distributed Destinations, JDBC Connection Pool, Server Performance, Thread Pool
Java EE Application Cache Monitoring
Database Server Number of maximum and average DB connections, connection time.

The rest of this article discusses the details of object cache monitoring and the process of building a JMX implementation.

JMX technology is gaining increasing attention in the area of application and server monitoring. JMX provides all the required tools for developing distributed, scalable, and modular solutions for managing and monitoring Java enterprise applications. JMX is based on MBeans (Managed Beans)?Java objects used for management needs?registered in a managed object server (an MBean Server), that acts as a management agent for monitoring purposes. You can use JMX monitoring locally or from a remote machine. Check out this article on how to remotely monitor a J2EE Cluster using Tomcat servers.

Here are the four main steps involved in a typical JMX implementation.

  1. Define an MBean interface
  2. Implement the interface on managed classes
  3. Register managed objects with an MBean server
  4. Monitor the objects using a JMX-compliant console

Object Cache Monitoring
Monitoring an object cache gives you insight into the details of the cache manages and stores objects, such as when objects are added to or removed from the cache. One important cache statistic is the hit-miss ratio, which is defined as the number of hits that successfully access data stored in the cache versus the number of misses. A “miss” occurs when the data isn’t cached, and the application must access the data from the backend database?either because this is the first request for that data, or because the cached data has expired. The higher the hit-miss ratio, the better the objects are being managed in the cache; thus the hit-miss ratio is a good measure of the effectiveness of the object cache.

Aspect-oriented Programming
AOP lets you add design and run-time behavior to objects in a non-obtrusive way using static and dynamic cross-cutting. The main advantage of AOP is that you can write the code for cross-cutting concerns such as persistence or business rules using Aspects, and apply it declaratively (via Annotations or XML configuration) in the existing code. You can also dynamically inject the code into plain old Java objects (POJOs) for any third-party software components even if you don’t have the source code or can’t modify the code due to licensing restrictions. Using AOP you can design and implement Utility and Infrastructure modules that are completely separated from the core application logic.

AOP offers a flexible and loosely coupled architecture as far as the application and infrastructure code are concerned. Areas in a typical Java EE application that can use Aspects are security, persistence, business, validation rules, and infrastructure code such as tracing, profiling, and performance management.

Monitoring and AOP
Monitoring is a good example of a cross-cutting concern. The integration of JMX and AOP provides a clean, centralized and reusable monitoring module in the application. You can dynamically add new monitoring capabilities in the application with minimal or no changes to the existing code. AOP provides the ability to enhance any part of the application with the code necessary to provide transparent application monitoring and management. You can define Aspects to monitor operations in the application and log the activity into MBeans to display monitoring information on a Web-based management console, all without touching any of the existing application code. You can also add support for notifications on property changes and registration with the MBean server.

AOP Monitoring Frameworks
Already, some interesting frameworks have appeared that use JMX and AOP to implement monitoring in Java enterprise applications. These frameworks can monitor run-time system optimization, application performance, SQL profiling, and other application areas. Here are a few of these monitoring frameworks, along with brief explanations of what you can accomplish with each.

  • SONAR is an acronym for System Optimization and Navigation with Aspects at Runtime. Developed using XML, dynamic AOP, and JMX technologies, SONAR provides a unified framework for runtime system optimization and navigation to monitor the enterprise applications at application, framework/middleware/virtual machine and operating system levels. You can use SONAR to add dynamic instrumentation to an application, and to monitor HTTP requests, database access calls, and JSP pages.
  • AWare is basically a set of reusable Aspects and AOP components for the AspectWerkz framework. It includes add-on Aspects for performance reporting with JMX, exposing runtime application performance to MBeans. The AWare framework offers Aspect components for various cross-cutting concerns such as management (using MX4J tool), search indexing (Lucene), role-based security, transaction demarcation, and persistence (Hibernate). Check out the AWare Web site for more details on these Aspect components.
  • The Chires framework uses AOP to introduce JMX MBean support into plain Java objects. It instruments the Java classes through byte code manipulation and by registering the objects when they are instantiated or when Java EE application lifecycle events occur. Developers can configure the monitoring functions using Annotations or XML. Chires provides JMX interfaces to monitoring statistics, state and operations without any code changes to existing application.
  • The DRIPS (which stands for Dynamic Rule based Instrumentation of Production Systems) project is part of BEA’s dev2dev CodeShare community. The DRIPS framework has a profiler tool that dynamically calculates the response time of methods in a Java class using AOP techniques (based on the Aspectwerkz tool). The profiling data can be broadcast via JMX notifications to other applications interested in the data.

Also, in a recent article on aspect-oriented performance monitoring framework, Ron Bodkin talked about the Glassbox Inspector tool developed using AspectJ and JMX technologies. He explained how this framework can be used for SQL profiling, monitoring the performance of database calls, and capturing statistics such as total number of SQL requests, total time taken, and worst-case performance for DB requests etc.

Cache Monitoring Using AOP
Adding the power of Aspects in the object cache monitor provides a loosely coupled and highly flexible and reusable module. Implementing an object cache monitor involves defining Aspects to intercept the calls to the cache at three join points:

  • Before an entry is added to the cache.
  • Before an object is explicitly removed from the cache
  • Both before and after an object expires or times out

For example, by intercepting the calls, you can check object size (in bytes) and raise warnings if an object exceeds the allowed size.

AOP Cache Monitor Framework
An ideal cache monitoring framework should not only be able to understand the cause of any cache management problems, but also proactively predict the problems related to cache size, memory usage, number of cached objects, etc. before they actually occur. In other words, the framework should accommodate the following requirements:

  1. It should provide a GUI based administration console for monitoring and managing the object cache with the ability to view and edit cache behavior.
  2. It should notify appropriate individuals or groups when exceptions are thrown when storing and purging the data stored in the cache.
  3. It should provide the ability to expire the cached data on demand (via a Web-based JMX console).
  4. It should allow transparent cache configuration for changing settings such as the maximum number of objects allowed in the cache, expiration time, eviction policy, and memory cap (in MB).
  5. It should provide reports and auditing information to monitor cache trends.
  6. It should be transparent to the other application layers.
  7. It should provide a loosely coupled architecture between the application code and cache monitoring code.
  8. It should be easy to maintain; cache monitoring code should be able to change without having any impact on application logic and vice-versa.

How Cache Monitoring Works
Here’s how the cache monitoring module works. Table 2 shows the steps involved when a client requests the data for the very first time and for subsequent requests.

Table 2: The table shows the steps required for both a first (uncached) request and for subsequent (cached) requests.

# Request Description Cache Monitoring Details
1 Initial request Client requests the data for the first time. Intercept the client request using a pointcut. Check if data is in the cache using around advice. When no match is found (because this is the first request), call the proceed() method of the join point to get the data from backend database. Store the result set in the object cache, update CacheMonitorMBean with miss count and other cache statistics, and finally, return data to the client.
2 Subsequent requests Client requests the same data again. Intercept the data request using the pointcut. Check if data is already present in the cache using the around advice. When you find a match update the CacheMonitorMBean with the hit count and other cache statistics, and return the data to client.
3 Data Expiry Cached data expires after a pre-defined timeout. This is pretty much same as step 1. First check to see if the data is in the cache. When no match is found call the proceed() method of the join point to get the data from the database.

Table 3 shows the pointcuts and advice you would write in an AOP Cache Monitoring framework.

Table 3: Here are the pointcuts and advice you would write in an AOP Cache Monitoring framework.

Aspect Type Aspect Name PointCut Advice
Caching ObjectCache.aj contextInitialized After
Caching JBossCache.aj contextDestroyed Before
Caching JBossCache.aj getInterestRates Around
Monitoring CacheMonitor.aj getInterestRates Around

You instantiate the object cache when initializing the Web application context , using a servlet context listener class called LoanAppContextListener. The code below shows the contextInitialized method in the listener class. The method doesn’t do anything other than display a debug message, but you can use this method as a join point to write an after advice to load the cache.

   //This method is invoked when the Web Application   //is ready to service requests   public void contextInitialized(      ServletContextEvent event) {      //Output a simple message to the server's console      sLog.debug("LoanApp context is created.");   }

Here’s the pointcut and after advice to call the initObjectCache method.

   @Pointcut("execution(void       LoanAppContextListener.contextInitialized(      ServletContextEvent)) && args(event)")      void contextInitialized(      ServletContextEvent event) {};   @After("contextInitialized(event)")      public void afterContextInitialized(         ServletContextEvent event) {         System.out.println("afterContextInitialized");         initObjectCache();      }

Similarly, you want to remove the cache object when the servlet context is destroyed. The code snippets below show the contextDestroyed method in the LoanAppContextListener class and the pointcut and before advice to cleanup the cache respectively.

   //This method is invoked when the Web Application   //has been removed and is no longer able to accept   //requests   public void contextDestroyed(      ServletContextEvent event) {      //Output a simple message to the server's console      sLog.debug("LoanApp context is removed.");   }   @Pointcut("execution(void       LoanAppContextListener.contextDestroyed(      ServletContextEvent)) && args(event)")      void contextDestroyed(      ServletContextEvent event) {};   @Before("contextDestroyed(event)")      public void beforeContextDestroyed(         ServletContextEvent event) {         System.out.println("beforeContextDestroyed");         cleanupObjectCache();      }

Technologies and Frameworks
The AOP Cache Monitoring framework layers use several different technologies and open source frameworks. Table 4 lists these frameworks and the application tier in which they are used.

Table 4: List of layers and technologies used in the AOPCacheMonitor framework.

Layer Technology
Presentation Spring MVC, JUnit, HttpClient
Application Spring Framework
Domain DAO
Infrastructure JBossCache
Tools JConsole, JBoss 4.0, Hypersonic SQL, Eclipse 3.1, AspectJ, AJDT 1.3

The sample application uses the JConsole tool that comes with the J2SE 5.0 installation as the JMX console for monitoring and management of the object cache and to display runtime JVM details such as heap size, memory usage, thread details, etc. Figure 1 shows the topology diagram for the Cache Monitor application.

 
Figure 1. AOP Cache Monitor Application Architecture Diagram: The diagram shows the topology of the Cache Monitor application.

You can wrap the existing value objects that need to be cached; they become JMX MBeans using introduction advice, which is used to add new attributes and methods to an existing class, thus dynamically providing additional functionality. Using the CacheMonitorAspect class, when an object is inserted in the cache, you save the statistics by triggering JMX notifications that update the cache details in the CacheMonitorMBean class, and display those statistics in a Web console.

Several object cache values can add value to application monitoring. The following list shows the statistics that the proposed cache monitoring framework will monitor:

  • hit count
  • miss count
  • cache object life (ms)
  • last access time
  • expiration time
  • list of objects by region name or fully qualified name (FQN)
  • expiration policy (purge algorithm)
  • cache replication time in the cluster

Building the Sample Application
The sample application for this article is based on an earlier object caching framework described in my article Object Caching With AOP. It’s a simple loan processing application where the interest rates for a specified product type (Mortgages or HELOC) are required to process the loan application information. It stores these interest rates in an object cache to reduce database calls and improve application performance. This article enhances the LoanApp module from the original project to add monitoring and management functionality.

You’ll find that different aspects tackle the object caching and JMX monitoring functions. These aspects are called ObjectCache.java, which defines the base cache methods, JBossCache.java, which defines caching logic using JBossCache API, and finally, CacheMonitor.java which implements the monitoring logic.

In Listing 1, the method called getInterestRates in the LoanAppHelper class retrieves interest rates from the database using JDBC calls. This is the method you want to intercept using an aspect to check if the data is already in the cache, retrieving it from the database only if the rates are not already cached.

Around advice intercepts any call to the getInterestRates method to check if the requested data is already present in the cache. Listing 2 shows the pointcut and around advice that handles the object caching functionality.

The following code sample shows how to add the MBean functionality to a plain Java object using the introduction advice. First, define an interface called CacheMonitorMBean and then write introduction advice to inject the JMX code into the InterestRates object. Here’s the interface code.

   public interface CacheMonitorMBean {     public CacheStats getCacheStats();     public void setCacheStats(CacheStats cacheStats);   }

And here’s the introduction advice.

   declare parents: InterestRates implements       CacheMonitorMBean;      public CacheStats getCacheStats() {      }      public void setCacheStats(CacheStats cacheStats) {         // Populate cache details      }

You also need a monitoring aspect (with around advice) to update the cache statistics whenever getInterestRates() method gets called. Here’s an excerpt of the monitoring aspect code. The around advice populates the cache monitor bean with the cache details.

   @Pointcut("execution(List       LoanAppHelper.getInterestRates(String)) &&       args(productGroup)")      void pcPrintCacheStatistics(String productGroup){};   @Around("pcPrintCacheStatistics(productGroup)")      public List aroundPcPrintCacheStatistics(         ProceedingJoinPoint thisJoinPoint, String          productGroup) {                  System.out.println(           "aroundPcPrintCacheStatistics");           long start = System.currentTimeMillis();        try {            printCacheStatistics();        } catch (Exception e) {            e.printStackTrace();        } catch (Throwable t) {            t.printStackTrace();        }         return null;     }

Testing the Application

 
Figure 2. Eclipse Window: This screenshot of the Eclipse window shows the AJDT build configuration.

You can compile and build the LoanProc application using an Ant build file (Refer to the build.xml file located in CacheMonitorAOP project’s main directory). The AJDT build configuration file injects the caching and monitoring logic. You can also run the AJDT build from the command line using parameters to specify which aspects can be woven into the application code. Figure 2 shows the AJDT build properties file (ajdt.properties) which you can use to enable or disable the Aspects?to weave or unweave those functions into the application code.

I’ve included a few JUnit test scripts in the sample code that you can use to test different object cache management scenarios. I also ran a performance test using JMeter to monitor the cache trends. After running the tests, you can view the cache monitor details using the JConsole program.

Using code like that in the sample application along with Aspects and JMX, you can introduce instrumentation into an object cache in a Java enterprise application without modifying any existing application logic. Although not implemented here, another feature of the framework that you should explore is cache invalidation, letting you invalidate cached objects on demand. For example, you might want to include cache invalidation capabilities as part of a Web-based administration tool.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: