About Vlad Mihalcea

Vlad Mihalcea is a software architect passionate about software integration, high scalability and concurrency challenges.

Caching best practices

Introduction

There is an irresistible attraction to writing custom caching solutions, since it seems to be the easiest path to “improving” the overall application performance. Well, caching is a great technique, but there are few steps to consider before even considering it.

Best practices

 
 
 

  1. A key/value collection is not a Cache

    Almost all projects I worked on have been using some sort of custom caching solutions, built on top of Java Maps. A Map is not an out-of-the-box Caching solution, since a Cache is more than a key/value store.
    A Cache also requires:

    • eviction policies
    • max size limit
    • persistent store
    • weak references keys
    • statistics

    A Java Map doesn’t offer these features and you shouldn’t spend your customer’s money to write a custom cache solution either. You should choose a professional cache like EHCache or Guava Cache, which are both powerful and simple to use. Those tools are constantly tested by all those projects employing them, so the code quality is higher than most custom built solutions.

  2. Use a cache abstraction layer

    A very flexible solution is the Spring Cache abstraction. The @Cacheable annotation allows you to separate the business logic code from the caching cross-cutting concern. The caching solution is therefore configurable and it’s not going to pollute your business methods.

  3. Beware of the caching overhead

    Every API has a cost and caching is no different. If you cache a web service or an expensive database call, then the overhead is probably negligible. If you use a local cache for a recursive algorithm, you need to be aware of the overall caching solution overhead. Even the Spring cache abstraction has an overhead, so make sure the benefits outweigh the costs.

  4. If your database queries are slow, the cache should be your last resort

    If you use an ORM tool like Hibernate, that’s the first place where your optimization process should start from. Make sure the fetching strategy is properly designed, and you don’t suffer from N+1 query problems. You could also assert the SQL statement count to validate the ORM generated queries.
     
    When you’re done optimizing your ORM SQL query generation, you should check your database for slow queries. Make sure all indexes are in place and that your SQL queries are effective. The indexes must always fit into RAM, otherwise you will hit the more expensive SSD or HDD. Your database has the ability to cache query results, so take advantage of it.  
     
    If the data set is large and the growth rate is high you could horizontally scale it on multiple shards.  
     
    If all of those actions are not enough, you may consider a professional caching solution such as Memcached.

  5. What about data consistency?

    When you start using a cache in front of your business layer, the data consistency constraint is being challenged. The benefits of ACID may be compromised if the cache is not properly synchronized with the database. This is like keeping a denormalized form of your actual data. If a root entity changes it may affect a large portion of your cache. If you discard the cache entries, all the caching benefits are lost. If you asynchronously update the cache entries you loose the strong data consistency, leaving you with an eventual consistent data model.

Playing time

Inspired by this very interesting post on the Java 8 computeIfAbsent Map addition, I decided to present you a Guava Cache alternative that has the following advantages:

  1. there is a fixed cache size of 2 entries
  2. it works with Java 1.6
private LoadingCache<Integer, Integer> fibonacciCache = CacheBuilder.newBuilder()
		.maximumSize(2)
		.build(new CacheLoader<Integer, Integer>() {
			public Integer load(Integer i) {
				if (i == 0)
					return i;

				if (i == 1)
					return 1;

				LOGGER.info("Calculating f(" + i + ")");
				return fibonacciCache.getUnchecked(i - 2) + fibonacciCache.getUnchecked(i - 1);
			}
		});

@Test
public void test() {
	for (int i = 0; i < 10; i++) {
		LOGGER.info("f(" + i + ") = " + fibonacciCache.getUnchecked(i));
	}
}

And the output is:

INFO  [main]: FibonacciGuavaCacheTest - f(0) = 0
INFO  [main]: FibonacciGuavaCacheTest - f(1) = 1
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(2)
INFO  [main]: FibonacciGuavaCacheTest - f(2) = 1
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(3)
INFO  [main]: FibonacciGuavaCacheTest - f(3) = 2
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(4)
INFO  [main]: FibonacciGuavaCacheTest - f(4) = 3
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(5)
INFO  [main]: FibonacciGuavaCacheTest - f(5) = 5
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(6)
INFO  [main]: FibonacciGuavaCacheTest - f(6) = 8
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(7)
INFO  [main]: FibonacciGuavaCacheTest - f(7) = 13
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(8)
INFO  [main]: FibonacciGuavaCacheTest - f(8) = 21
INFO  [main]: FibonacciGuavaCacheTest - Calculating f(9)
INFO  [main]: FibonacciGuavaCacheTest - f(9) = 34

 

Reference: Caching best practices from our JCG partner Vlad Mihalcea at the Vlad Mihalcea’s Blog blog.
Related Whitepaper:

Software Architecture

This guide will introduce you to the world of Software Architecture!

This 162 page guide will cover topics within the field of software architecture including: software architecture as a solution balancing the concerns of different stakeholders, quality assurance, methods to describe and evaluate architectures, the influence of architecture on reuse, and the life cycle of a system and its architecture. This guide concludes with a comparison between the professions of software architect and software engineer.

Get it Now!  

Leave a Reply


three + 5 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close