Traffic on our system has been increasing, putting more pressure on our database causing the response time of our application to degrade. Since we are currently using Hibernate in our project for a Java app that surfaces a REST API, we decided to look into caching strategies available. After looking around and trying a few technologies we decided to tested out the open source version of Terracotta.
To start let’s just explain the difference between First Level Caching and Second Level Caching in Hibernate.
First level caching is associated with the Session object and is caching on a per transaction basis. An example would be an object where you make several updates to it as part of a single transaction. Hibernate, rather than submitting several update statements to the database, will pool the group of updates to the object into a single update statement.
Second level caching is associated with the SessionFactory object and maintains a cache of previously loaded objects accross transactional boundaries. These cached objects are available to any query for the same object, not just a single transaction. So in this case the entire application has access to retrieve any cached object. For example, if my app performs a lookup for a Product object describing a product, if the application later makes a request for the same product, this object can be retrieved from the Second-level Cache rather than making an additional trip to the database.
Handles asynchronus queueing of writes. This feature offers some failover capabilities for when our database is not available. Originally we attacked the problem separately figuring we needed a caching strategy for reads and a fault tollerant queuing strategy for writes to deal with our current single point of failure (our database). Fortunately Terracotta has functionality that allows us to cover both of these cases.
The Developer Console. This tool allows you to monitor the traffic between your app, the Terracotta server, and your database. With the Developer Console we were able to test out different caching strategies to see which ones gave us the highest percentage of cache hits. For us developers, this was a major plus, having such a useful tool to aid us in tuning our cache settings. It made Terracotta feel much less like a black box.
Simple to install and configure. Since Terracotta just plugs in to Hibernate, there is no real development work required to get it up and running. Setting up a Terracotta server is easy, adding it to the application just meant minor additions to our pom.xml file and our hibernate settings file, and tuning our cache settings was relatively simple using the provided Developer Console.
Install and Start the Terracotta Server
- Download Terracotta
- Install by running the command: java -jar terracotta-3.1.0-installer.jar
- Start the Terracotta server: ~/terracotta/terracotta-3.1.0/bin/start-tc-server.sh
- Start the developer console: ~/terracotta/terracotta-3.1.0/bin/dev-console.sh
Add Terracotta support to your Maven/Java/Hibernate/Spring Application
- Add the Terracotta dependencies to your Maven pom.xml file
<dependency> <artifactId>terracotta-hibernate-agent</artifactId> <version>1.0.0</version> <groupId>org.terracotta.hibernate</groupId> <scope>provided</scope> </dependency> <dependency> <artifactId>terracotta-hibernate-cache</artifactId> <version>1.0.0</version> <groupId>org.terracotta.hibernate</groupId> </dependency>
<bean id="sessionFactory"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <props> ... <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.provider_class"> org.terracotta.hibernate.TerracottaHibernateCacheProvider </prop> ... </props> </property> ... </bean>
Running your project with Jetty
In our local development environments we use Jetty as our web server (Tomcat on production). To run your app from Maven using the Jetty plugin make sure you first do the following:
- Set the MAVEN_OPTS environment variable with the “javaagent” parameter
export MAVEN_OPTS="-javaagent:/path/to/terracotta-hibernate-agent-1.0.0.jar -cp /path/to/terracotta-hibernate-cache-1.0.0.jar -Xmx512m"
Overall we have found Terracotta to be a useful tool. It requires very little effort to update an existing project using Spring/Hibernate to use it. Terracotta offers more than just Second Level Caching, but also handles queuing of writes and ensuring data is written to the SOR (System or Record) in the event the database is not available for a brief period. Also, stale cache entries are not an issue as well since Terracotta updates the cache immediately on any write made to the SOR. As a final note, the Developer Console is a really nice addition!
I hope this post helps!