Apache Camel: Use of Cache with Caffeine
By: Daniel S. Blanco
Tags: Microservices, Cache, Rest Api, Apache Camel, Caffeine

Caffeine Structure

We are going to see how to improve the performance of our web services in Apache Camel. To do this we will use Caffeine Cache, a simple but powerful memory cache made in Java and based on Guava’s cache.

The idea behind the use of the cache will be to be able to store the result of expensive operations in memory. In this way, in successive calls, we will be able to access this result in a fast and agile way of avoiding the expensive operation.

Let’s start as always by indicating which are the libraries to be included. On the one hand, the dependency to use Caffeine and on the other hand, the Spring starter that provides us with a default configuration.

<dependency>

<groupId>org.apache.camel.springboot</groupId>

<artifactId>camel-caffeine-starter</artifactId>

</dependency>

<dependency>

<groupId>org.apache.camel</groupId>

<artifactId>camel-caffeine</artifactId>

</dependency>

How does it work? We must think about the cache as if it were a ConcurrentMap. That is, we will be placing objects associated with a certain key, and through that key, we will be able to recover them. Therefore, to be able to use it, we will use actions of type GET or PUT associated with a key. The message body will be the object stored in the cache.

When we make some operation Caffeine will indicate to us if this operation has been successful and if there is any result associated with it. This information will be given to us through values stored in the header: CamelCaffeineActionSucceeded and CamelCaffeineActionHasResult. Caffeine also has an interface, called CaffeineConstants, with all the constants associated with its operations or results that can help us in the development.

Next, we will see the example to obtain a book based on its identifier. The identifier will serve as a key to store the associated book in the cache. First, we will check if it is in the cache (GET action), in this case, we will return the associated value. Otherwise, we will make the database query operation and store the result in the cache (PUT action) for future queries.

If we do a test, we will see that the times and performance with Caffeine are better. If we compare it using hey, even being a very basic operation we see how the times are reduced a lot:

Comparison between calls

But we have to take into account what would happen if the result of that expensive operation changed. In such a case the cache would still work and return a wrong value. To avoid that, we have different options:

First option: through the configuration, with which we can modify how many results and how long they will be kept in memory.

Second option: directly invalidate the cache. Easy solution. For example, in the case that we delete an object, we do not want that cache to continue to exist and return wrong results. This can be done through the INVALIDATE action.

Finally, we will see the option of how an application should behave when the cached object is updated. The easy solution would be to invalidate the cache associated with the key and re-cache it when it is invoked again. But this option will make us perform one more expensive operation than necessary. If we already have the object, we could simply store it again in the cache and avoid that future expensive operation. Here we have an example with the PUT method.

That’s all, as you can see if very easy to use and the benefits are clear. As always you can see all the code, here.