Grails on Terracotta using Ehcache

September 5, 2010 at 8:48 pm
filed under Ehcache, Grails, Groovy, Terracotta

These days, much talk goes into making your applications scale better. With the internet growing rapidly, and large companies investing vast sums of money into presenting their goods to the world, we need to become more innovative in how we handle these large volumes of traffic. Somehow, our single small instance of Tomcat fronted by a little Apache just won’t cut it any more!

So how do you go about scaling an application out? More specifically, how do you scale a Grails application? In the Java landscape we have several great clustering technologies to choose from. The product that I tend to levitate towards is the open source Terracotta. This is a practical guide to scaling out a Grails application with Terracotta using Ehcache integration.

Configure your Application

Firstly, we need to get our application ready for working with Terracotta. As expected, Terracotta (almost) doesn’t impose on your code. Here’s how I got it all working:

Step 1: Implement Serializable
All domain classes should implement java.io.Serializable. There is no need to import it because it’s already provided by Groovy!

package my.app
 
class Person implements Serializable {
    String firstName
    String lastName
 
    static constraints = {
    }
}

Step 2: Make Domain Classes Cacheable
All domain classes to be clustered should be marked as cacheable in the mapping closure of the class.

class Person implements Serializable {
...
    static mapping = {
        cache true
    }
}

Step 3: Add the Terracotta Maven Repository
This is done in the BuildConfig.groovy file. Locate the repositories section and update the following:

repositories {
...
    //uncomment mavenCentral
    mavenCentral()
...
    //add terracotta repos
    mavenRepo “http://www.terracotta.org/download/reflector/releases”
}

Step 4: Introduce the Ehcache and Terracotta Dependencies
This can be done easily using the dependency resolution DSL in the grails-app/conf/BuildConfig.groovy file. Find the inherits("global") section and update as follows:

inherits(“global”) {
    // uncomment to disable ehcache
    // excludes ‘ehcache’
    runtime ‘net.sf.ehcache:ehcache-core:2.4.2′
    runtime ‘net.sf.ehcache:ehcache-terracotta:2.4.2′
    runtime ‘org.terracotta:terracotta-toolkit-1.2-runtime:3.1.0′

Step 5: Configure Ehcache to use Terracotta
Create a file called ehcache.xml in the grails-app/conf folder. This will create an Ehcache CacheManager called MyCache, and will give you some defaults to begin working with. Refer to the ehcache website to add cache configurations per Domain class in your app.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="MyCache" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="ehcache.xsd">
 
   <defaultCache
      maxElementsInMemory="1000"
      eternal="false"
      overflowToDisk="false"
      diskPersistent="false"
      timeToIdleSeconds="1200"
      timeToLiveSeconds="1200">
          <terracotta />
   </defaultCache>
 
   <terracottaConfig url="localhost:9510" />
 
</ehcache>

The import things to look out for are the terracotta tags in this file.
The first lies within the defaultCache tags, and marks it to be clustered by Terracotta.
The second lies within the ehcache tags, and specifies where to find the terracotta server. More about that in a minute…

Step 6: Add a Custom Cache Configuration
Next, we will add a cutom cache config for our Person class. This is simply done by adding a set of cache tags to the ehcache.xml file right beneath the defaultCache tags.

...
  <defaultCache
  ...
  </defaultCache>
 
  <!-- Add the custom cache config here -->
  <cache name="my.app.Person" maxElementsInMemory="1000"
      maxElementsOnDisk="10000" eternal="false" timeToIdleSeconds="3600"
      timeToLiveSeconds="0" memoryStoreEvictionPolicy="LFU">
      <!-- Adding this element turns on clustering for myCache. -->
      <terracotta />
  </cache>
...

One final thing…

It’s very important to use a persistent database for this exercise to succeed. We will need to open our grails-app/conf/DataSource.groovy file and update it as follows, using the HSQLDB file database, in update dbCreate mode.

...
environments {
    development {
        dataSource {
            dbCreate = "update" // one of 'create', 'create-drop','update'
            url = "jdbc:hsqldb:file:devDB"
        }
    }
    test {
...


Let’s have some fun!!!

That’s it. Most of the hard work is done, and we are now ready to start testing our clustered Grails app!

Let’s head on over to the Terracotta Site and download the Terracotta Binary Distribution. Unpack it to a convenient place (usually in /usr/local) and start up the server in a terminal.

$ /usr/local/terracotta-3.3.0/bin/start-tc-server.sh

Next, fire up the Terracotta dev console:

$ /usr/local/terracotta-3.3.0/bin/dev-console.sh

You can now start your grails app, and should see it connecting to the terracotta server running locally. Click on the Ehcache button and select the Statistics tab. This should pop up a confirmation, answer yes to this. I created a few People using the scaffolding in Grails:

I then refreshed the Person List page in the browser MANY times in order to get the result below. As you can see, I had a 99% hit ratio!


Now for the fun bit! Stop and start your Grails app! Once it’s started up and connected to Terracotta again, try refreshing the Person List page and watch what the console has to say (remember to click refresh on the console): No misses and several hits! 100% Hit ratio, with NO database access!


Well, that’s it in a nutshell! Terracotta and Grails, one happy couple. In a subsequent post, I will write about setting up a cluster of Grails apps with several Terracotta servers. You will see that running a cluster is as easy as setting up a single instance like we did in this post.

Let me know your thoughts, and please share any other experiences you might have.
Enjoy it and have lots of fun,
Cheers,
Marco.

Source Code of the above example is available here.

Fork me on GitHub

13 comments

RSS / trackback

respond

 
  1. Blog bookmarks 09/08/2010 « My Diigo bookmarks

    on September 8, 2010 at 6:24 am

    [...] Grails on Terracotta using Ehcache | mycodesnippets.com [...]

  2. Egon

    on September 8, 2010 at 5:24 pm

    I downloaded the source code and typed grails run-app, but only got this:

    ::::::::::::::::::::::::::::::::::::::::::::::

    :: UNRESOLVED DEPENDENCIES ::

    ::::::::::::::::::::::::::::::::::::::::::::::

    :: net.sf.ehcache#ehcache-core;2.2.0: not found

    :: net.sf.ehcache#ehcache-explicitlocking;0.2: not found

    ::::::::::::::::::::::::::::::::::::::::::::::

  3. Marco

    on September 9, 2010 at 6:22 pm

    Hi Egon,
    I just tried running it on a clean machine, and it worked fine for me.
    In the past I’ve seen this sort of thing happening when the ivy cache gets corrupted on your local machine. Try moving away (or deleting) your .ivy folder in your home directory.
    Hope that helps,
    Cheers,
    Marco.

  4. Egon

    on September 10, 2010 at 5:48 am

    No, it doesn’t help :-(
    I have tried to download and run the code on 2 different machines: Mac OS X and Windows Server 2003, and both gives the same error.
    Also I removed my .ivy dir, but still I get the same error.
    I was using Grails 1.3.4 and I tried to switch to 1.2.4, but still with the same error.

  5. Egon

    on September 10, 2010 at 1:45 pm

    I found a solution.
    I manually downloaded ehcache-core-2.2.0.jar and ehcache-explicitlocking-0.2.jar to my-app/lib.
    Then I deleted ~/.ivy2 and ~/.grails as they still caused problems.
    Now grails run-app finally works :-)

  6. Lucas Teixeira

    on September 15, 2010 at 11:09 pm

    Actually, you’ll need just to uncomment the line

    mavenCentral()

    in your BuildConfig.groovy, this way ivy will resolve it.

    :)

    great article

  7. ehcache.net

    on December 28, 2010 at 3:48 am

    Grails on Terracotta using Ehcache…

    These days, much talk goes into making your applications scale better. With the internet growing rapidly, and large companies investing vast sums of money into presenting their goods to the world, we need to become more innovative in how we handle thes…

  8. rockhowse

    on June 21, 2011 at 9:15 pm

    Using these directions with Grails 1.3.7

    The versions of the libraries have changed. Here is the new inherits(“global”) section:

    inherits(“global”) {
    // uncomment to disable ehcache
    // excludes ‘ehcache’
    runtime ‘net.sf.ehcache:ehcache-core:2.4.2′
    runtime ‘net.sf.ehcache:ehcache-terracotta:2.1.1′
    runtime ‘org.terracotta:terracotta-toolkit-1.1-runtime:2.0.0′
    }

    Note the exclusion of the following:

    runtime ‘net.sf.ehcache:ehcache-explicitlocking:0.2′

    As of ehcache-core 2.4 the explicitlocking has been added to the core.

    Here is the new repositories section:

    repositories {
    grailsPlugins()
    grailsHome()
    grailsCentral()

    // uncomment the below to enable remote dependency resolution
    // from public Maven repositories
    //mavenLocal()
    mavenCentral()
    //mavenRepo “http://snapshots.repository.codehaus.org”
    //mavenRepo “http://repository.codehaus.org”
    //mavenRepo “http://download.java.net/maven/2/”
    //mavenRepo “http://repository.jboss.com/maven2/”
    // terracotta repos
    mavenRepo “http://www.terracotta.org/download/reflector/releases”
    }

    Noe that the following has been uncommented:

    mavenCentral()

    By default this section is commented out a default grails 1.3.7 application.

  9. Marco

    on July 2, 2011 at 3:25 pm

    Thanks for that, I’ve updated the post accordingly.

  10. rockhowse

    on July 10, 2011 at 8:40 am

    This gets even more fun =P If you want to connect to terracotta 3.5.1 the version of ehcache-core (2.4.x+) no longer uses this class on init:

    net/sf/ehcache/transaction/xa/EhcacheXAStore

    Because of this you need to make sure that the global section is much more up to date:

    inherits(“global”) {
    // uncomment to disable ehcache
    // excludes ‘ehcache’
    runtime ‘net.sf.ehcache:ehcache-core:2.4.2′
    runtime ‘net.sf.ehcache:ehcache-terracotta:2.4.2′
    runtime ‘org.terracotta:terracotta-toolkit-1.2-runtime:3.1.0′
    }

    Very confusing because this information is scattered across the net >.<

    This issue is outlined here:

    https://jira.terracotta.org/jira/browse/EHC-826

    If you could update the section accordingly that would be great! Awesome article BTW it really helped me get going with ehcache and grails!

  11. Eric

    on August 31, 2011 at 10:51 pm

    Have you tried getting non-stop caching to work? http://ehcache.org/documentation/terracotta/non-stop-cache We’ve been unsuccessful so far getting caching to operate in a non-stop mode.

  12. Iván López

    on October 26, 2011 at 1:13 pm

    Hello,

    could you please provide a zip with a working project?. I’m using grails 1.3.7 and I’ve configured all like you and when I run grails-app I get the following exception:

    Configuring Spring Security …
    2011-10-26 14:05:23,161 INFO – Terracotta 3.5.1, as of 20110420-070421 (Revision 17477 by cruise@kong from 3.5.1)
    2011-10-26 14:05:23,962 INFO – Successfully loaded base configuration from server at ‘localhost:9510′.
    2011-10-26 14:05:24,030 INFO – Successfully loaded base configuration from file at ‘/tmp/tc-config6472372029898811811.xml’.
    2011-10-26 14:05:24,078 INFO – Log file: ‘/home/ivan/terracotta/client-logs/terracotta-client.log’.
    java.lang.NullPointerException
    at com.tc.object.config.StandardDSOClientConfigHelperImpl.setupL1ReconnectProperties(StandardDSOClientConfigHelperImpl.java:1953)
    at com.tc.object.config.StandardDSOClientConfigHelperImpl.getL1ReconnectProperties(StandardDSOClientConfigHelperImpl.java:1966)
    at com.tc.object.DistributedObjectClient.getReconnectPropertiesFromServerOrExit(DistributedObjectClient.java:407)
    at com.tc.object.DistributedObjectClient.start(DistributedObjectClient.java:445)
    at com.tc.object.bytecode.ManagerImpl$2.execute(ManagerImpl.java:262)
    at com.tc.lang.StartupHelper.startUp(StartupHelper.java:39)
    at com.tc.object.bytecode.ManagerImpl.startClient(ManagerImpl.java:280)
    at com.tc.object.bytecode.ManagerImpl.init(ManagerImpl.java:200)
    at com.tc.object.bytecode.ManagerImpl.init(ManagerImpl.java:188)
    at com.tc.object.bytecode.hook.impl.DSOContextImpl.createStandaloneContext(DSOContextImpl.java:179)
    at org.terracotta.express.StandaloneL1Boot.call(StandaloneL1Boot.java:190)
    at org.terracotta.express.ClientImpl.(ClientImpl.java:309)
    at

    Regards, Iván.

  13. Marco

    on October 26, 2011 at 5:35 pm

    Hi Ivan,
    I have never come across this one before, although it seems to be internal to Terracotta. If you carefully look again at the end of my article you will find a link to the source code.
    Cheers,
    Marco.