Developing Reactive Microservices with Spring Data and Distributed SQL

Nikhil Chandrappa

Ecosystem Software Engineer

In 2016 in the keynote presentation of Spring One Platform, Juergen Hoeller announced Spring WebFlux, one of the most highly anticipated projects being worked on by the Spring Team due to the performance gains that reactive streams promised for web controllers. Subsequently, with Spring Framework 5.0, Spring Reactive MVC went GA along with the release of WebFlux API, making the reactive stream based web controller mainstream.

Fast-forward to 2020, Spring WebFlux MVC has gained wide adoption in cloud native applications, where developers strive for high throughput and low latency microservices. Clearly there has been a shift towards the reactive programming model, now that many of the database providers support reactive drivers where traditional blocking database calls are replaced by async and non-blocking back pressure aware data access.

In this blog post, we will walk you through the basics of getting started with a fully reactive tech stack, from web controllers to database calls. We will build a Spring microservice using Spring WebFlux, Spring Data Reactive Repositories, and YugabyteDB, which supports reactive drivers for CRUD operations.

What’s YugabyteDB? It is an open source, high-performance distributed SQL database built on a scalable and fault-tolerant design inspired by Google Spanner.

The technology stack to build a Spring microservices application

By following this tutorial, we will build a Spring microservices application exposing the reactive REST API for performing CRUD operations against YugabyteDB. This sample application uses following tech stack:

  • Spring WebFlux – Support for reactive MVC controllers and REST controllers.
  • Spring Data reactive for Apache Cassandra – Reactive repositories support for YugabyteDB.
  • Yugabyte Cloud Query Language (YCQL) – A SQL-based, flexible-schema API that supports distributed transactions, strongly consistent secondary indexes, and a native JSON column type. YCQL is compatible with the query dialect of Apache Cassandra and works natively with Apache Cassandra reactive drivers.

The Git repo for the sample application is here.

Starting YugabyteDB

Start the YugabyteDB cluster using the following command from YugabyteDB installation directory:

$ ./bin/yb-ctl destroy && ./bin/yb-ctl --rf 3 create --tserver_flags="cql_nodelist_refresh_interval_secs=10" --master_flags="tserver_unresponsive_timeout_ms=10000"

This will start a 3-node local cluster with replication factor (RF) 3. The flag cql_nodelist_refresh_interval_secs configures how often the drivers will get notified of cluster topology changes and the following flag tserver_unresponsive_timeout_ms is for the master to mark a node as dead after it stops responding (heartbeats) for 10 seconds.

Note: Here are the complete instructions for installing YugabyteDB on your local Mac laptop.

Project initialization and dependency configuration

Create a new Spring Boot project using Spring Initializr and add the following dependencies required for the sample application:

  • Spring Reactive Web
  • Spring Data Reactive for Apache Cassandra

On reviewing the pom.xml of the project, you will see the following reactive dependencies:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-cassandra-reactive</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Reactive repository configuration

Spring Boot auto reconfiguration initializes the Cassandra datasource on startup, all we have to do is to specify the YugabyteDB connection information in application.properties as shown below:

spring.data.cassandra.keyspace-name=sample
spring.data.cassandra.contact-points=127.0.0.1
spring.data.cassandra.port=9042

Once we have the datasource configuration applied, let’s go ahead and review the reactive repositories required for the sample application.

The sample application contains the product domain object, for which we will be creating reactive repositories for performing CRUD operations. The domain object should have the @Table and @Id annotations of Spring Data Cassandra:

@Table("products")
public class Product {

	@Id
    private String productId;

    ...
}

Now let’s implement a reactive repository for the product domain object:

public interface ProductReactiveRepository extends ReactiveCassandraRepository<Product, String> {

}

The ReactiveCassandraRepository interface enables reactive APIs for all the common operations Spring Data supports like save( ), findById( ), findAll(), and deleteByID(). As you might expect, these API calls will return reactive types, either Mono<> or flux<> based on the result of the API call.

Reactive REST controller and data access

As we saw from the previous section, all boilerplate code for datasource creation and implementing the data access code is provided by the Spring Framework. Let us now use the product repository in our reactive REST controller.

@RestController
public class ProductController {

	@Autowired
	private ProductReactiveRepository productReactiveRepository;

	@GetMapping("/products")
	public Flux getProducts() {
		return productReactiveRepository.findAll();
	}

	@PostMapping("/products/save")
	public Mono createProductUsingSaveAPI(@RequestBody Product product) {
		return productReactiveRepository.save(product);
	}
}

That’s it! Controller methods which are using the repository APIs are also returning reactive types, which makes the overall interaction asynchronous, from serving the http request to database call, giving applications performance benefits of having a fully reactive programming model.

Summary

As cloud native applications shift towards a non-blocking programming model, application developers can quickly start prototyping using Spring abstractions for reactive programming. And coupling that with distributed cloud native databases like YugabyteDB, which support reactive drivers for data access, will result in highly scalable and performant applications.

What’s next?

Nikhil Chandrappa

Ecosystem Software Engineer

Related Posts

Explore Distributed SQL and YugabyteDB in Depth

Discover the future of data management.
Learn at Yugabyte University
Get Started
Browse Yugabyte Docs
Explore docs
PostgreSQL For Cloud Native World
Read for Free