Aerospike is a flash-optimized in-memory open source NoSQL database. Unlike another popular NoSQL storage Redis, Aerospike is multithreaded and supports cross data center replication(XDR). In this tutorial we will explore how to build a gRPC service with spring boot and gradle that uses aerospike as the backend.
Bootstrap The Project
Bootstrap The Project
We will start by generating project structure using Spring Initializr. On the spring Initializr page, select the following,
- Project — Gradle Project
- Language — Java
- Spring Boot — 2.33
- Packaging — Jar
- Java — 11
- Dependencies
Lombok
Spring Security
Spring Boot Actuator (Optional)
Spring REST Docs (Optional)
Spring Web
Generate the project structure, download the code and open it in Intellij (You may use your editor of choice)
Gradle Configuration
We need to make few changes in the build.gradle file to enable protobuf support for gRPC and Aerospike. Full gradle configuration can be found here
gRPC Support
For gRPC, we will use proto compiler to auto-generate java code from .proto file.
- Add following in the plugins
id 'com.google.protobuf' version '0.8.12'
- Add a sourceSets section to define where to find auto-generated classes
sourceSets { main{ java { srcDir 'src/main/protoGen' } }}
- Add a protobuf section to for protobuf compiler
- Add following code in gradle dependencies
implementation 'io.github.lognet:grpc-spring-boot-starter:3.5.6'
Aerospike Support
We will use spring-data-aerospike to access aerospike storage. Add following in the gradle dependencies
implementation 'org.springframework.data:spring-data-commons' implementation 'com.aerospike:spring-data-aerospike:2.4.0.RELEASE'
Project Structure
The project contains 3 main directories for proto file, auto-generated code and other java classes.
main/Java
Java directory contains 4 packages.
- com.nur.spring.aerospike.configuration
configuration packages, as the name implies, contains various configuration classes. AerospikeRepositoryConfiguration is used to configure target aerospike cluster, user credentials and namespace. SecurityConfiguration controls url permission. - com.nur.spring.aerospike.domain
domain classes are populated by the repositories with data fetched. - com.nur.spring.aerospike.repository
contains repository interface definition. It is worth noting that there is no need to provide implementation classes of these interfaces. Proxy implementations are generated during compilation. - com.nur.spring.aerospike.service
Service classes implement business logic. There are two types of service classes.
1. GrpcService - GrpcService classes are annotated with @GrpcService. They intercept incoming requests.
2. Service — Service classes are annotated with @Service. They implement business logic.
main/proto
proto directory contains .proto files.
main/protoGen
protoGen directory contains all the classes generated by proto compiler.
Execution Flow
As usual the execution flow is initiated by the client. Client request is intercepted by GrpcService class. Grpc service class calls various service classes to process the request. Services needing data from aerospike calls repository.
Access Aerospike
As mentioned before the project uses spring data aerospike to access aerospike storage. Spring-data-aerospike is built on spring data API. Much of the complexity is abstracted away and is taken care of by the library leaving simple repository interfaces to interact with aerospike backend.
- The library provides AerospikeRepository<T, ID> where
T — the domain type the repository manages
ID — the type of the id of the entity the repository manages
- The interface can be extended to create a new interface to manage specific domain types.
- Domain type T is used as the aerospike set name.
- ID is the key to query
- Each field in the domain type represents a bin in aerospike.
public interface StorefrontProductRepository extends AerospikeRepository<StorefrontProductDocument, String> {}
Declaration above creates an interface that lets us query aerospike by string type key into a set represented by document entity GreeterDocument.
Defining document entity
Document entity represents the domain model. In the context of aerospike, a set represents domain (similar to a table that represents a domain in relational database world). Following example explains how the document entity is mapped to the aerospike set and bin.
@Value // (1)
@Document(collection = “my_aerospike_set”) // (2)
@AllArgsConstructor
public class GreeterDocument {
@Field(“my_aerospike_greeting_bin”) // (3)
String GreetingText;
}
Explanation
- @Value — makes the class immutable, all fields are made private and final, toString(), equals(), hashCode(), field getters and all args constructor are generated.
- @Document(collection = “my_aerospike_set”) — @Document marks a class as an entity to be persisted in aerospike, By default, class name is used as the aerospike set name but this can be overridden by collection element as is done in the example above.
- @Field(“my_aerospike_greeting_bin”) — configures the name of a field to be used when persisting the document. This value will be used as a bin name instead of the original field name.
Source code
The full source code can be found in github.