Caching with Spring Boot and Aerospike

Roi Menashe
Aerospike Developer Blog
6 min readMay 22, 2021
Photo by John Salvino on Unsplash

In this article you will see an example of a Spring Cache application backed by an Aerospike database.

Source code can be found here:

1. Introduction

Spring Cache with Aerospike database allows you to use annotations such as @Cacheable, @CachePut and @CacheEvict that provides a fully managed cache store using an Aerospike database to store the cached data.

In this example we are going to use these annotations on a UserRepository class methods to create/read/update and delete user’s data from the cache.

We will see that if a user is stored in the cache — calling a method with @Cacheable annotation will fetch the user from the cache instead of executing the method’s body that responsible for the actual user fetch from the database, if the user doesn’t exist in the cache it will fetch the user’s data from the database and put it in the cache for later usages (a “cache miss”).

With Spring Cache and Aerospike database we can achieve that with only few lines of code.

2. Motivation

Let’s say that we are using another database as our main data store, for example, Microsoft SQL Server. we don’t want to fetch the results from SQL Server every time we request the data, instead we want to get the data from a cache layer.

There are number of benefits for using a cache layer, here are some of them:

  1. Performance— Aerospike can work purely in RAM but reading a record from Aerospike in Hybrid Memory (primary index in memory, data stored on Flash drives) is extremely fast as well (~1ms).
  2. Reduce database load— Moving a significant part of the read load from the main database to Aerospike can help balance the resources on heavy loads.
  3. Scalable — Aerospike scales horizontally by adding more nodes to the cluster, scaling a relational database might be tricky and expensive, so if you are facing a read heavy load you can easily scale up the cache layer.

3. Project

3.1 Setup

We will use docker for our Aerospike database and Spring Boot Initializr to setup our project, if you don’t already have an environment ready — check out steps 1 and 2.1 of the following article on how to setup what you need:

https://medium.com/aerospike-developer-blog/simple-web-application-using-java-spring-boot-aerospike-database-and-docker-ad13795e0089

3.2 Dependencies

We need to add spring-data-aerospike dependency.

Add the following dependency to the pom.xml file:

<dependency>
<groupId>com.aerospike</groupId>
<artifactId>spring-data-aerospike</artifactId>
<version>3.0.0</version>
</dependency>
  • This article is relevant for spring-data-aerospike version 3.0.0/2.5.0 and above.
  • Make sure to load maven changes after adding the dependency

3.3 Code

We will not use an actual database as our main data store (SQL Server) for this demo, instead we will simulate a database access by printing a simulation message and replace a database read by just returning a specific User.

3.3.1 Configuration

AerospikeConfigurationProperties

AerospikeConfiguration

In the AerospikeConfiguration we will create two types of Beans:

AerospikeClient

Responsible for accessing an Aerospike database and perform database operations.

AerospikeCacheManager

The heart of the cache layer, to define an AerospikeCacheManager you need:

  1. aerospikeClient (AerospikeClient)
  2. aerospikeConverter (MappingAerospikeConverter)
  3. defaultCacheConfiguration (AerospikeCacheConfiguration), a default cache configuration that applies when creating new caches. Cache configuration contains a namespace, a set (null by default meaning write directly to the namespace w/o specifying a set) and an expirationInSeconds (AKA TTL, default is 0 meaning use Aerospike server’s default).
  4. Optional: initalPerCacheConfiguration (Map<String, AerospikeCacheConfiguration>), You can also specify a map of cache names and matching configuration, it will create the caches with the given matching configuration at the application startup.
  • Note: A cache name is only a link to a cache configuration.

3.3.2 Objects

User

3.3.3 Repositories

UserRepository

  • The cache annotations requires a “value” field, this is the cache name, if the cache name doesn’t exist — by passing initialPerCacheConfiguration param when creating a Bean of AerospikeCacheManager in a configuration class, it will configure the cache with the properties of the given defaultCacheConfiguration (3.3.1 Configuration > AerospikeCacheManager).

3.3.4 Services

UserService

3.3.5 Controllers

UserController

3.3.6 Add @EnableCaching

SimpleSpringbootAerospikeCacheApplication

Add @EnableCaching to the class that contains the main method.

4. Test

We will use Postman to simulate client requests:

4.1 Add User (@CachePut)

a. Create a new POST request with the following url: http://localhost:8080/users

b. Add a new key-value header in the Headers section:

Key: Content-Type

Value: application/json

c. Add a Body in a valid JSON format:

{
"id":1,
"name":"guthrie",
"email":"guthriegovan@gmail.com",
"age":35
}

d. Press Send.

And we can now see that this user was added to the cache.

4.2 Read User (@Cacheable)

a. Create a new GET request with the following url: http://localhost:8080/users/1

b. Add a new key-value header in the Headers section:

Key: Content-Type

Value: application/json

c. Press Send.

4.3 Remove User (@CacheEvict)

a. Create a new DELETE request with the following url: http://localhost:8080/users/1

b. Add a new key-value header in the Headers section:

Key: Content-Type

Value: application/json

c. Press Send.

And we can now see that this user was deleted from the cache (thanks to the @CacheEvict annotation in the UserRepository).

4.4 Cache miss — Read User that is not in the cache (@Cacheable)

We can use the GET request that we configured before with an id that we know for sure that is not in the cache (yet).

Lets try calling the get request with the id 5:

We got the following user’s data for the request id 5:

{
"id": 5,
"name": "jimmy page",
"email": "jimmy@gmail.com",
"age": 77
}

If you remember correctly we wrote it hard-coded in the UserRepository to simulate an actual database fetch of a user id that doesn’t exist in the cache.

We can now also see that the user was added to the cache.

Conclusion

This was a demonstration of how simple it is to create a basic cache layer with Aerospike database using Spring Boot caching.

You can do much more with Spring Boot and Aerospike database, check out this medium article on how to start a simple web application using Java, Spring Boot, Aerospike and Docker.

https://medium.com/aerospike-developer-blog/simple-web-application-using-java-spring-boot-aerospike-database-and-docker-ad13795e0089

--

--