J2EE object-caching frameworks

Improve performance in Web portal applications by caching objects

1 2 3 Page 2
Page 2 of 3
  • Element grouping
  • Quick nested categorical removal
  • Data expiration
  • Fully configurable runtime parameters
  • Remote store recovery
  • Scheduled cache expiry
  • Security (Authentication or authorization should be completed before objects return from the cache. The information transmitted between caches should be encrypted.)

In this article, I compare three open source object-caching frameworks in terms of their installation and configuration complexity, flexibility, and future extensibility. The following table provides a brief description of each of these frameworks.

Table 1. Overview of selected frameworks

Caching frameworkVendorURLOverview
Java Caching SystemJakarta (part of Jakarta Turbine project)http://jakarta.apache.org/turbine/jcsJava Caching System (JCS) is a highly flexible and configurable solution to increase overall system performance by maintaining dynamic pools of frequently used objects. JCS goes beyond simply caching objects in memory. It provides several important features necessary for an enterprise-level caching system. JCS provides a framework with no point of failure, allowing for full session failover (in clustered environments), including session data across up to 256 servers. It also provides the flexibility to configure one or more data storage options like memory cache, disk cache, or caching the data on a remote machine.
OSCacheOpenSymphonyhttp://www.opensymphony.com/oscache/OSCache caches sections of JSP pages and binary content such as PDFs or images. It provides both fast in-memory caching and persistent on-disk caching depending on the caching requirements. It also supports object caching in a cluster environment.
JOCacheShiftOnehttp://jocache.sourceforge.netJOCache was developed to provide basic object caching. It supports clustered caching and can integrate with OR (object relational) models such as Hibernate.

Table 2 shows a comparative summary of these three frameworks.

Table 2. Comparison of caching frameworks

FeatureJCSOSCacheJOCache
JCache (JSR-107) compliant?YesYesYes
Installation and configuration complexitySimpleSimpleSimple
Supports cache regionsYesYesYes
Schedule cache expiryNoYesYes
Configuration filename (format)cache.ccf (plain text)oscache.properties (plain text)cache.properties
jar filejcs-1.0-dev.jaroscache-2.0.jarshiftone-cache.jar
Available cache algorithmsLRU, MRULRU, FIFO, UnlimitedFIFO, LRU, LFU
Clustering supportNoYesNo

Proposed Web portal caching framework

Before I started designing the object-caching framework for this article, I made a list of objectives that needed to be accomplished:

  • Faster access to frequently used data in the Web portal application.
  • Grouping of similar object types in the cache. The framework should invalidate a collection of objects with a single operation. It should be possible to associate objects in the cache so they can be managed as a group. In particular, invalidating a group of objects with one call should also be feasible.
  • Configurable cache management so I can modify cache parameters declaratively rather than programmatically.
  • Easy integration into any Web application with minimal or no changes in the Web application itself.
  • Seamless expiration mechanism. The hard part of expiration should be in the framework. Using the framework to expire objects should be as easy as possible.
  • The caching system shouldn't require the objects it stores to understand timestamps and know when they are out of date.
  • A flexible and extensible framework so I can switch to any third-party caching API in the future.
  • Flexibility to configure one or more data storage options, such as memory cache, disk cache, or caching the data on a remote machine.
  • Ability to generate statistics to monitor both caching effectiveness and application performance improvement as a result of data caching.
  • Ability to manage objects loaded from any source. The original source of the data being cached should have no restrictions.

The architecture diagram in Figure 1 shows the main components of the Web portal application using object caching.

Figure 1. Caching application architecture diagram. Click on thumbnail to view full-sized image.

Installation and configuration

Table 3 lists the hardware and software specifications of the machine used to test the caching frameworks.

Table 3. Hardware and software specifications

ProcessorHP Pavilion Pentium III with 800 MHz
Memory374 MB RAM
Hard Disk40 GB
Operating systemWindows 2000 Server with Service Pack 4
JDK version1.4.0_02
Tomcat version5.0.18
Tools usedAnt 1.6.1, log4j

Main elements of an object-caching framework

A typical caching framework contains components such as a CacheObject, CacheObjectKey, Cache, CacheManager, and a CacheLoader. I designed this article's caching framework so that a single CacheManager class encapsulates all the implementation details of caching, such as the access, creation, and destruction of objects in the cache from the client applications.

Java classes

Figure 2 illustrates the relationship of the Java classes in the caching framework.

Figure 2. Caching framework class diagram. Click on thumbnail to view full-size image.

Listed below are the Java classes that a Web application must know to use the caching functionality. These classes are located in the common.caching package in the source code provided with this article, which can be download from Resources.

ICacheManager

ICacheManager is the main interface (contract) that a client program uses to handle all the operations related to caching (i.e., storing, accessing, and releasing the data in the cache). The client program can be a JSP (JavaServer Pages) page, a Struts action class or a POJO (plain old Java object). This interface was created to hide all the caching implementation details from the client so if we needed to switch to a different third-party caching API in the future, we wouldn't need to change any of the client code.

BaseCacheManager

BaseCacheManager is the main class in the Web portal caching framework. It's the base implementation of ICacheManager. This class was created to centralize all the cache-related methods in one class. It's designed as a singleton to ensure one and only one instance of ICacheManager is created in the servlet container's JVM. In a clustered environment where multiple Web server/servlet container instances accept Web requests, a separate ICacheManager instance will be created in each JVM. If we switch to a different caching API later, this is the only class that must be modified to work with the new cache API. Also, if we switch to a JCache-compliant caching implementation, the cache manager should require minimal changes.

ICacheLoader

The ICacheLoader interface implements the actual data-access logic in the Web client. All client programs that need to use the caching mechanism must implement this interface. It has one method called loadCacheObject() and takes two input parameters, a string to specify the cache region name and an object to specify the cache key. This way, the cache manager knows which client program to use (to execute loadCacheObject()) to reload the object in the cache when the cached data expires after the specified time-to-live has elapsed.

It is good practice for the caching service to load objects automatically as needed rather than using the application to directly manage objects that use the cache. When an application directly manages objects, it uses the CacheAccess.put() method to insert objects into the cache. To take advantage of automatic loading, we instead use a CacheLoader object and implement its load method to put objects into the cache.

Note that the caching framework does not handle the creation of objects that need to be cached in a Web application, i.e., the data-access logic that retrieves the data from the data source is not coded in the caching classes. It relies on the client program to define the actual data-access logic. Technologies like Java Data Objects (JDO) are typically used to encapsulate the data-access logic in an enterprise Web application.

ICacheKey

The ICacheKey interface was created to hide the specific logic used to create a cache key. Sometimes the cache key may not be a simple string. It may be as complex as the combination of multiple objects, and getting these values from the data source involves not one, but several, lookup methods. In this case, ICacheKey can define all the complex logic involved in creating the cache key. This way, the cache-key creation logic is defined in a separate class. I wrote a sample class called TestCacheKey that implements this interface and overrides the getCacheKey() method to illustrate how to use this interface.

CacheRegion

A CacheRegion is defined as an organizational namespace for holding a collection of cache objects. Objects with similar characteristics (such as time-to-live and business use) should be cached in the same cache region so they can all be invalidated simultaneously if needed. To eliminate any synchronization issues that could cause poor performance, I used a separate instance of Cache for each cache region.

Configuration files

We configure all the caching parameters in a properties file. These parameters include caching information such as maximum number of objects that can be stored in memory, time-to-live (after which, the cached data is automatically released from memory), idle time (elapsed time since last access time), and memory cache name (caching algorithm such as LRU or MRU). Make sure the properties file is copied in a directory that's in the classpath.

Figure 3 shows the portal application's Web request flow in a sequence diagram.

Figure 3. Caching application sequence diagram. Click on thumbnail to view full-size image.

Testing setup

I created a build script using Ant to compile all Java source code for the object-caching framework. The Ant build script, named build.xml, is located in the WEB-INF/classes directory. I also wrote a JUnit test client to test different caching scenarios using the Web portal caching framework. This test script called CachingTestCase is located in the WEB-INF/classes/common/caching/test directory. Extract the sample code to a new Web application directory. To compile the Java code and run the JUnit test script, run the following commands:

  • ant common.compile (to compile all Java classes included in the caching framework)
  • ant common.runjunit (to run the JUnit test script; the test script uses log4j to display all of the output messages)

I wrote nine different JUnit test cases to test the criteria, such as performance, multiple cache regions, and cache expiration. Table 4 lists these test cases.

Table 4. Caching test cases (JUnit)

Test case numberTest case NameDescription
1testBasicCachingStore an object in cache and verify it's in the cache
2testLoadFromCacheStore an object in cache, sleep for a specified time less than the cached object's TTL, and retrieve object from cache to verify it's still in the cache.
3testCachePerformanceStore an object in cache and retrieve it 10 times to determine the performance gain in caching the object versus accessing it from the data source
4testStoreRetrieveClearStore three different objects in cache using three different keys, retrieve them using the keys, then remove the objects from cache and verify their removal.
5testMultipleCacheRegionsStore an object in two different cache regions, sleep for specified time periods, retrieve object from cache, and finally clear the cache regions.
6testCacheExpiryStore an object in cache, sleep for a specified time longer than the cached object's TTL, and try to retrieve the object in cache to verify it's already removed from the cache.
7testCachingUsingCustomCacheKeyStore an object in cache using a custom cache key and retrieve the object using that cache key.
8testLRUMemoryCacheAdd items to cache, retrieve them, and remove them. The item count is more than the memory cache's size, so items should be dumped based on the LRU policy.
9testMultipleStoreRetrieveClearStore, retrieve, and clear objects in cache in many iterations to compare the performance of each caching framework.

Sample code

The sample code used in this article can be downloaded from Resources. Extract the zip file's contents to the Tomcat Webapps directory. You will need the following jar files in the classpath to run the test scripts.

  1. jcs-1.0-dev.jar
  2. oscache-2.0.jar
  3. shiftone-cache.jar
  4. log4j-1.2.8.jar
  5. junit-3.8.1.jar
  6. commons-logging-1.0.3.jar
  7. commons-lang-1.0.1.jar

Conclusion

I found that OpenSymphony's OSCache framework performs better than the other two caching frameworks within the specified test parameters. OSCache was twice as fast as JCS and 5 to 10 percent faster than JOCache. JOCache came in second in terms of caching performance. Table 5 shows the response times for Test Case 9 (testMultipleStoreRetrieveClear).

Table 5. Results for Test Case 9

(All response times are in milliseconds)

Number of iterationsJCSOSCacheJOCache
2,0003,1042,1332,224
4,0008,1324,5566,029
6,00016,7749,71410,344

All three frameworks were easy to install and simple to integrate into the Web portal application. The caching framework I created was flexible to allow for switching the caching implementation with minimal changes in the client code.

The exact gain in performance varies significantly depending on the cost of creating or acquiring the object and the ratio of reads to writes. The more costly the object is to create and the more reads per write, the greater benefit the cache can provide.

Caching should be applied carefully when other means, such as optimizing the acquisition of the resource itself, cannot be further improved. Caching can introduce some complexity, complicating the maintenance of the overall solution. Therefore consider the trade-off between performance and complexity before applying caching.

1 2 3 Page 2
Page 2 of 3