So you want Distributed, Scalable and Highly Available Cache?
Abstract
So you want Distributed, Scalable and Highly Available Cache? If yes, then this is the right place for you. The Terracotta Ehcache release has these features inbuilt. The Express Installation mode has simplified Terracotta integration in your application.
How this post is organized
First we shall start with simple standalone cache and then see how Terracotta can easily help us create a Distributed, Scalable and Highly Available cache, with a few minor configurations
What all do you need run the example?
- Terracotta 3.2.0 - Download it from here
Sample Application
Lets design a sample application (a real simple one), which we shall use to demonstrate the features. Device Monitoring is a common requirement in OSS System, and caching the Device information reduces the Database hits. The essential components of our application are
- DevideInfo - A POJO that stores device information
- CacheHandler - Class that handles cache initialization and other ops
Lets see the CacheHandler class, which is the heart of our implementation
public class DeviceInfo implements Serializable {
String deviceId;
String name;
// .... other device information
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
}
The class is simple and contains information related to the device.
Let see our CacheHandler class
public class CacheHandler {
public Cache deviceCache;
public void initCache() {
// Initialize the CacheManager
CacheManager cacheManager = CacheManager.create();
// Get the Cache to store device information
deviceCache = cacheManager.getCache("deviceCache");
}
public void addToCache(DeviceInfo device) {
Element el = new Element(device.getDeviceId(), device);
deviceCache.put(el);
}
protected int getDeviceCacheSize() {
return deviceCache.getSize();
}
public static void main(String[] args) {
CacheHandler handler = new CacheHandler();
handler.initCache();
// Lets add 10 devices
// just to keep life simple
for(int i = 0; i < 10; i++) {
DeviceInfo device = new DeviceInfo();
device.setDeviceId("Device-"+i);
handler.addToCache(device);
}
// Not recommended in production
System.out.println("Cache Size = "+handler.getDeviceCacheSize());
}
}
The class has two main functions
- initCache - The API initializes the cache
- addToCache - The API adds the device information to the device cache
Lets see our ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="deviceCache"
maxElementsInMemory="1000000"
maxElementsOnDisk="1000"
eternal="false"
overflowToDisk="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
memoryStoreEvictionPolicy="LFU">
</cache>
</ehcache>
In the configuration we have defined a deviceCache, that we shall use to store device information.
Following is the list of jars you would need to run this app
- ehcache-core-1.7.2.jar
- slf4j-api-1.5.8.jar
- slf4j-jdk14-1.5.8.jar
All these jars are available as part of Terracotta installation under
You can run this example and see the same in action.
Making it Distributed....
Now lets assume that we want to make the Cache fault tolerant, survive JVM crashes, as well as have it available on different JVM's. It should be able to Scale as we add more JVM's to it and other stuff. With Terracotta, we can just do it in a few steps without changing the code. the magic lies with Express Installation mode, introduced in Terracotta version 3.2.0 and above
Lets see the 3 steps that we need to perform
1. Updates to the ehcache.xml
Add following element to ehcache.xml
<terracottaConfig url="localhost:9510" />
and for the deviceCache, we add <terracotta /> element
here is the updated ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
<terracottaConfig url="localhost:9510" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="deviceCache"
maxElementsInMemory="1000000"
maxElementsOnDisk="1000"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
memoryStoreEvictionPolicy="LFU">
<terracotta />
</cache>
</ehcache>
There is no need to change the code
2. Add ehcache-terracotta-1.8.0.jar to the classpath
Lets start the Terracotta Server
3. Goto Terracotta_Install_dir/bin and execute
$ ./start-tc-server.sh
This shall start the Terracotta server
Now run the application on multiple JVM's. The device information is available on all client JVM's
To monitor Cache, you can use Terracotta Dev Console
If you have further question/queries, please visit Terracotta Forums.
What's coming up Next?
The next post shall touch on write-behind feature in the latest Terracotta Darwin release. Its essentially to get best of both worlds - Caching and Database Offloading
Stay tuned..
