Configuring Azure Redis Cache to boost Spring Boot performance

Suthesana
5 min readSep 4, 2020

--

A better solution for scaling would be to “Scale out”: rather than replacing our instance by a much bigger one, we are getting to add more instances. this enables for greater scalability (at some point you cannot buy a much bigger instance…), and is far more cost-efficient as we’ll only run the amount of instances we’d like , automatically.

For this, Azure proposes a “Scale out” option which is simply under the “Scale up” option, and where you’ll found out rules to scale out. For instance , here i’ve defined a rule: when 70% of the CPU is employed for quite 10 minutes, then we’ll automatically launch new instances, with a maximum of 20 instances:

This setup will allow our application to scale up and down automatically, depending on our workload. But this is just one part of the problem.

The database is the problem

Scaling out is awesome, but most of the time performance issues come from the data base. As we have worked on this issue for decades, this is the reason why the JHipster team focuse so much on using a cache, as it’s the best way to eliminate this data base issues.

options are in terms of data store performance:

We can buy a more expensive instance for our data store: in fact this may work, a minimum of for a few time, just like the like the “scale up” mechanism . The main issue here is that we want to be budget-conscious, and a quick check on the prices of high-end database instances cause you to search for other solutions.

We can use the NoSQL databases typically CosmosDB. CosmosDB is a distributed, very efficient database which will scale out automatically. This is a great option, but it will requires to change our current database and depend upon Azure: this is not the topic of this series, but be sure we will do a specific CosmosDB post in the future, as it’s a very exciting technology.

Use the Hibernate 2nd level cache: this is the caching mechanism that included inside the Hibernate, and it’s extremely powerful when used correctly. This is able to be our recommended solution, however the difficulty here is that we are going to scale out, which requires us to have a distributed cache.

Use the Spring Cache abstraction: it’s a really simple mechanism, yet very powerful, that permits you to cache method calls. This will be more powerful than the Hibernate 2nd level cache when used correctly, because it’s works at the business level, so it can cache more complex objects. As for Hibernate, this may require us to use a distributed caching solution.

The last two options are the best solution for our use-case, but they both require us to posses a distributed caching solution, otherwise as soon as our Azure Web App instance scales out, we’ll see some invalid data.

Cashing options and issues

In Java, we usually have 3 type of caches:

Local-JVM caches: they’re the fastest, as getting data is typically just using a pointer to that data, that is directly available in the memory. But they take memory from the JVM heap: as our cache grows, the JVM’s garbage collector will have more and more trouble to pass, leading to poor application performance.

Off-heap caches: they run in another process, next to the JVM. in order that they don’t use the network, yet they require data to be serialized/unserialized because it moves between two processes, which is sort of costly. So this cache is much slower than the local-JVM cache, but it can grow to gigabytes of data without affecting the JVM.

Remote caches: they’re like off-heap caches, but run on another server. This usually allows to possess even bigger caches (as they’re found out on specific high-memory instances), but are going to be slower as they require a network access.

Several well-known solutions are exist, and are usually supported by JHipster:

Ehcache, which is unfortunately doesn’t have an API to scale out (you cannot add new nodes once the cluster is created).

Hazelcast and Infinispan, which may scale using an API, but which requires a mechanism so new nodes register to the existing cluster. This is often what JHipster provides with the JHipster Registry.

Here, we are going to use Redis, which may be a well-known in-memory data store that’s often used as a cache. Compared to Hazelcast and Infinispan, it’s some unique options:

It is only used as a “remote cache”, so it can store more data, and it’ll not pollute our JVM, but it’ll be slower for very frequently-used data.

As a managed service, it’ll “scale out” automatically, removing the necessity for something just like the JHipster Registry to possess nodes register within the cluster.

It is fully Open Source, so you’ll use it to store huge amount of knowledge without having to buy the “enterprise version”.

Azure Cache for Redis

Azure Cache for Redis is a fully-managed Redis cache, hosted by the Azure.It has a very inexpensive first tier and in fact it can grow to an enormous , distributed cache with geo-replication if you spend extra money .

Setting up an Azure Cache for Redis

Go to Azure portal and just use the search box to create it

Configuring Spring Boot and Azure Cache for Redis

First we have to add the spring-boot-starter-data-redis library to our pom.xml:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Next we have to add a specific Spring Boot configuration class, so Redis only works in production mode. In development mode, everything will work in equivalent without the cache, and thta will make our development setup easier:

package io.github.jdubois.bugtracker.config;

import io.github.jhipster.config.JHipsterConstants;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@EnableCaching
@Profile(JHipsterConstants.SPRING_PROFILE_PRODUCTION)
public class CacheConfiguration {
}

And we have to configure Redis in our application-prod.yml Spring Boot configuration file:

spring:
cache:
type: redis
redis:
ssl: true
host: spring-on-azure.redis.cache.windows.net
port: 6380
password: Y27iYghxMcY1qoRVyjQkZExS8RaHdln4QfLsqHRNsHE=

In order to test our code, we have to add some cache in a REST method of the ProjectResource class:

@GetMapping("/projects")
@Cacheable("projects")
public List<Project> getAllProjects() {
log.error("REST request to get all Projects");
return projectRepository.findAll();
}

This is just for testing, as you’ll quickly have cache invalidation issues with this code , but it’ll make it easy for you to check that your cache works well

Once this is done, we should be able to monitor your cache through the Azure portal:

Next topic: Deploy Angular app with azure blob storage

--

--