Tuesday, September 27, 2011

Spring Performance With Annotations and Ehcache ARC

The goal of this blog is to highlight Ehcache's new ARC feature using Spring Annotations.

Terracotta is releasing Ehcache 2.5. It's biggest new feature is ARC (Automatic Resource Control). ARC brings runtime performance tuning and caching to the Systems Administrator while simplifying it for the Developer. I've written a couple of blogs describing what it is and the value it brings:
These two blogs and the Ehcache docs are excellent sources of information on these highly requested/useful new capabilities. 

Getting Started

I wanted to give a brief demonstration of how someone would leverage Ehcache ARC in practice so I pinged the guys who do Spring Annotations and they OK'd me to leverage one of their samples. Spring Annotations enable one to mark methods that do performance sensitive operations to be cached to improve the application's speed. 

In order to follow along with me you'll want to read up on and check out the Spring Annotations sample here: 

Download it and play with it a bit to get familiar with how it works.

This sample is fairly self contained. It show's how to use the various annotations to improve performance in a simple and concise way. What it doesn't talk about is the configuration of the underlying cache in use. This ends up being very challenging in practice. Without help you'll run into at least a few of these 5 problems:

  • Crash - Out of Memory Errors can crash your Application
  • Pause - Long GC's will pause your application leading to an unpredictable user experience
  • Wasted Space - In order to avoid the above two problems you over provision memory wasting ton's of space
  • Tuning Hell - Either you or your users spend ton's of time making arbitrary decisions trying to balance out the memory usage of your caches to avoid the above 3 issues
  • Poor Performance - Caches don't really help because they are incorrectly sized

Let's look at the ehcache.xml that ships with this sample:

The important parts of this config are from lines 30-31. It sets maxElementsInMemory to 100 and timeToLiveInSeconds to 300.

Why do these need to be set? Let's look at them individually:


When you started your Tomcat instance some amount of memory was reserved in the command line (Xms Xmx). If you didn't set a maxElementsInMemory your cache would grow infinitely until long GC's and then an OOME occur. So maxElementsInMemory is a resource management choice. But why 100? Is it because you know how big your entries are and you know 100 is exactly some percentage of the heap? More likely it's a guess. Probably a low ball guess so that you don't OOME wasting a whole bunch of heap. Now say you have 10's or 100's of caches that hold objects of varying size. How much harder is it to set the maxElementsInMemory now?

timeToLiveInSeconds = 300

This is a data freshness control. If your using an unclustered cache and multiple nodes then objects are likely being updated in a DB and the data in your cache can get out of date. How out of date? Depends what you set your timeToLiveInSeconds to.
NOTE: Keeping all nodes up to date is one of the reasons people use clustered caches.

Configuring a cache using the above controls makes an application sensitive to use case changes, changes in JVM heap settings, and number of caches. It also leaves the user of the application with a choice of leaving a lot of headroom to handle the worst case, risking OOME's and forcing the admin or user to tune at every deployment.

Ehcache ARC Gets Performance Without All The Tuning

These are the problems that Ehcache ARC, the most requested feature in Ehcache history, are designed to eliminate. Ehcache ARC makes your cache or caches controllable using the same metric the JVM's are started with. The same resource you are trying to manage. Bytes! In addition, instead of having to tune each individual cache you can instead make a high level choice at the CacheManager level and let ARC balance the resources for you.

In this change to the sample we have removed the cache entry count and instead allowed the cache to use 50% of the JVM heap (look at line 4 where it says maxBytesOnHeap). This setting tells the cache manager to allow for up to 50 percent of the heap for caching (Can also be configured using a fixed number of bytes instead of percentage). It will balance this heap across what ever caches are defined with this manager. This allow's an application to manage the available resources without waste and without GC pauses/OOMEs.

I updated and rebuilt my spring-annotations to use 2.5.0 and then rebuilt the sample using my newly created version of Ehcache Spring Annotations. You can grab the updated Jar here though I suspect the Spring Annotations guys will update the official build soon.

By using this approach as you add more and more @Cachable annotations to your application you don't have to change anything about the caches you create in ehcache.xml. They make use of the available cache resources as provided.

Wrapping Up

It has always been pretty easy to integrate a cache into an application. Things like Spring Annotations move the bar on that simplicity even further. The challenge was to make those caches effective. How does one get the most performance out of the resources available. Ehcache ARC was created to solve that problem for System Administrators, OEM's Developers and the entire OSS community. We are looking forward to people getting started with it and hope to receive lots of feedback.