Microservices: Caching with Redis and Memcached

This is the last part in our series about microservices development with Spring Cloud. In the last part, we discussed how to add performance metrics to microservices. Today, we’ll see how to actually improve performance using cache.

Caching in microservices with Spring

Spring framework provides a feature called cache abstraction. It’s s set of annotations that define common set of methods to operate on cache storage. Advantage of this approach is that you define caching parameters on your beans, and you can use any underlying caching mechanism supported by Spring. In fact, you can change caching providers by just changing some configuration entries, without the need to touch the code.

In this section, we’re gonna modify messaging service to use caching by means of cache annotations. We will add new endpoints which will be used to test this setup.

Configure service to use caching

The goal of caching is to improve performance. If we have some lengthy operation, such as big database query, we can use cache to store the data so we can quickly retrieve it on subsequent requests. Since we intentionally kept our system simple, and thus have no database available, we will simulate long lasting operation by putting a thread to sleep. You can find the complete source code for this series on Github.

Create slow service

Code sample bellow simulates slow running service:

Method getSomeValue  is annotated with @Cacheable  annotation, which means that return value of this method is cached. This is rather simple method, so we set only the cache name which will hold this value. In real world applications, we will need some kind of key to identify different values for different input parameters, but for our case, this will be sufficient.

In order to simulate lengthy operation, we set the running thread to sleep for 3 seconds. The first time we invoke this method, it will take about 3 seconds to get the current time. After that, each time we invoke the method, it will return almost immediately. You will also notice that for each call, the same time is returned, because we cached that value the first time method is called.

Another important point is the ability to invalidate the cache. For example, when database values are updated, we need a way to tell the cache that existing value it olds are no longer valid. In order to do that, we can use @CachePut  annotation. This annotation will cause the return value of the method to be placed in cache instead of the previous value.

In our example, we created update() method annotated with @CachePut . Each time this method is called, it will replace existing time in cache with new current time.

Create controller endpoints for testing

We now need a way to invoke these methods from the controller. In our MessageController , add the following two methods:

Here, we simply call two new endpoints to invoke cacheable methods. Endpoint /time  will return the time from cache, while /update  will invalidate the cache and place new value in it.

Enable caching support

We are still missing an important thing. This code will not work unless we enable caching support in Spring Boot. In order to do that, we need to annotate Application  class with @EnableCaching . This annotation tells Spring to check for available caching annotations and configure caching support correctly. So, we only need to add this annotation to Application  class:

 

Use Redis as cache

OK, so far, we have a solid base for caching support. What we need to do now is configure Redis server and connect our service to it. Fortunately, this is easy task, because Spring comes with out-of-the-box support for Redis.

Redis is an in-memory data store, which is frequently used as distributed cache. It can also be used as database and message broker, but in this case, we’ll use it as caching system.

Run Redis image from Docker

We will skip installing Redis, since it is out of the scope of this tutorial. Instead, we will use Docker image to run Redis server. You will need to have Docker installed on your machine to complete this part of the tutorial.

Official Redis image can be found on Docker Hub. To run this image, simply run the following in terminal:

This will start Redis container and expose the service at port 6379. You now have fully functional Redis server without any hassle. Pretty cool, huh?

Configure and run our microservices

All we need to do now is to tell our messaging service where to find Redis server. This is as simple as adding the following lines to application.properties file:

Now we are ready to roll!!! Start up Eureka server and messaging service. If you invoke http://localhost:8900/time , you will notice that the first time it will take some time before response is returned. Each subsequent request is processed almost immediately, because values are stored in cache now. You will also notice that each request returns the same time value.

If you now invoke http://localhost:8900/update , it will invalidate the cache and place new time in it. Try calling the /time endpoint again and note that value is changed. The output should be like in the image bellow:

 

microservices caching redis

 

Use Memcached as cache solution

Memcached is distributed caching system widely used for it’s simplicity and ease of deployment. It is most commonly used to speed up web applications by reducing database load. Unlike Redis, Spring boot does not provide out of the box support for Memcached. Fortunately, there are third party libraries which  provide easy integration of Spring and Memcached.

Setup Memcached Docker image

Just like in previous section with Redis, we will use Docker image of Memcached to avoid local installation and setup. We’ll use official Memcahed image from Docker Hub. Simply type the previous command in your terminal:

This command will start Memcached server in default port 11211.

Add required dependencies

Now it is time to add required dependencies to our microservices. We’ll use Brian Matthew’s starter package. Simply add the following snippet to messaging service POM.

This will set up default configuration for integration with Memcached.

Configuring microservice for Memcached

Using this starter, it is very easy to configure caching. Simply add the @EnableMemcached  annotation to main application class.

By default, starter expects Memcached server to be present at localhost and listens to port 11211. You can set a custom list of servers by adding the following configuration property to application.properties  file:

Now we are ready to test our setup. Just like in previous section about Redis, we can call endpoints we created and see how caching impacts performance.

Conclusion

In this post, you’ve seen how we can add caching support for distributed system based on microservices. Redis and Memcached are two popular solutions for caching, and we’ve seen how to use both of them with Spring Boot.

In my experience, Redis was recently  gaining more popularity over Memcached for new projects. Because of that, and the fact that it’s officially supported by Spring Boot, I believe it is better suited for use in Spring based applications.

Bellow you can find the links to all posts in this series about microservices:

Leave a Comment

Your email address will not be published. Required fields are marked *