Skip to main content

SpringBoot : Performance War


Reactive Systems are designed to address challenges posed by modern software systems - the challenges related to large number of users and high throughput. Reactive systems are expected to be highly responsive, resilient, elastic and message driven.

In this article we will:
  1. Build a set of fully non-blocking REST API using SpringBoot 2.0, WebFlux and Reactive Redis.
  2. Performance test the above Reactive APIs against the traditional non-reactive APIs.
The code used in this example can be downloaded from GitHub

Step 1: Create a skeleton Reactive WebFlux SpringBoot project

Create a SpringBoot maven project using - https://start.spring.io/
Add the following dependencies:
  • spring-boot-starter-web
  • spring-boot-starter-data-redis
  • spring-webflux
  • spring-boot-starter-data-redis-reactive

Refer to the dependencies in pom.xml

Step 2: Create Domain Objects

The demo project uses the domain objects Customer and Account. A customer can have multiple accounts.







Step 3: Create non-blocking reactive REST APIs using WebFlux

Create a REST controller CustomerControllerRx for the purpose of serving the following reactive no-blocking APIs.
  • Add/update a Customer
  • findById a Customer
The code snippet use Mono which is an implementation of Reactive streams Publisher interface and ReactiveRedisTemplate and ReactiveValueOperations to interact with Redis in a non-blocking way.
@RestController
@RequestMapping("/customers/rx")
public class CustomerControllerRx {
    @Autowired
    private ReactiveRedisTemplate redisTemplate;
    private ReactiveValueOperations reactiveValueOps;
   
         @PostMapping
         public Mono add(@RequestBody Customer customer) {
                 
                  reactiveValueOps = redisTemplate.opsForValue();

                  Mono result = reactiveValueOps.set(customer.getExternalId(), customer);
                  return result;
         }
         @GetMapping("/{id}")
         public Mono findById(@PathVariable("id") String id) {
                  reactiveValueOps = redisTemplate.opsForValue();

                  Mono fetchedAccount = reactiveValueOps.get(id);
                  return fetchedAccount;
         }
}


ReactiveRedisTemplate is configured in RedisConfigRx

Step 4: Create synchronous (blocking) REST API.

Create a REST controller CustomerController for the purpose of serving non-reactive blocking APIs. We are using CustomerRepository which extends a CurdRepository to interact with the Redis database.

@RestController
@RequestMapping("/customers")
public class CustomerController {
   
    @Autowired
    CustomerRepository repository;

    @PostMapping
    public Customer add(@RequestBody Customer customer) {
        return repository.save(customer);
    }

    @GetMapping("/{externalId}")
    public Customer findById(@PathVariable("externalId") String externalId) {

        Customer optCustomer = repository.findByExternalId(externalId);
       
        if (Optional.ofNullable(optCustomer).isPresent())
            return optCustomer;
        else{
            return null;
        }
    }
}
// Code for CustomerRepository
public interface CustomerRepository extends CrudRepository {

    Customer findByExternalId(String externalId);
    List findByAccountsId(Long id);
}

Step 5: Connecting to Redis using Docker.

·      Redis doesn’t officially support Windows. However, the easiest way to get Redis up and running for UNIX or Windows is by using Docker.
·      Use the following steps to pull a redis image from docker hub and to start on port 6379 in detached mode.
$ docker pull redis  
$ docker run -d -p 6379:6379 --name redis1 redis
$ docker ps -a           // make sure redis is up and running.
·      Enter the Docker shell for Redis
$docker exec -it redis1 sh
$redis-cli                     // enter into CLI mode
$keys *                        // list of keys
Refer to application.yml for Redis connection properties.
You may use the $docker-machine ip command to find the IP address of your docker machine, where the Redis database is running.

Step 6: Set up JMeter for testing

·       Install Apache jMeter https://jmeter.apache.org/
·       Install the following graph plugins from the plugin downloads site https://jmeter-plugins.org/
o   Basic Graphs
o   Additional Graphs
The above plugins are zip files and can be extracted to the lib folder of the JMeter installation folder. Once the plugins are installed, JMeter can be started from the bin folder.
The next step is to create Test Plans for the APIs that are required to be benchmarked. I have the following Test Plans for the APIs.


GetCustomers.jmx
To performance test non-reactive CustomerController : findById () method.
Get Mapping
SaveCustomers.jmx
To performance test non-reactive CustomerController : add () method.
PostMapping
GetCustomersRx.jmx
To performance test reactive CustomerControllerRx : findById () method.
Get Mapping
SaveCustomersRx.jmx
To performance test reactive CustomerControllerRx : Add () method.
PostMapping


The above Test Plans can be opened in JMeter and configured for different number of concurrent users – E.g.  5, 50, 100, 400, 500 and so on. Once its configured, JMeter test cases can be fired against the application in non-UI mode as below.
jmeter -n -t  <TestPLan.jmx> -l <TestPlan.jtl>  -e  -o
Where:
-n           à run in non-GUI mode
              -t            à provide the name of the test file
              -l            à name of the output report file
              -e           à jMeter to follow post processing specified in jmx file.
              -o           à dashboard folder.

Step 6: Benchmark reactive REST APIs vs blocking REST APIs

Start SpringRedisReactiveApplication
a)    Make sure the application starts without errors by connecting to the Redis DB on docker.
b)   Set no of users (threads) and loops (iterations) for the Test Plans.
Open the TestPlan using JMeter UI and change the number of users (threads) and set the number of loops. Save the test plan. Exit JMeter UI.
c)    Execute Test Plans
Go to JMeter\bin folder and execute:
jmeter          -n -t  \SaveCustomers.jmx
                                    -l                 \SaveCustomers.jtl
                                    -e -o             \SaveCustomersOutput-5Users
The above command will run SaveCustomers.jmx TestCases, creates a reporting folder named SaveCustomersOutput
d)   Repeat step 6 (b) and 6 (c) for the other test plans also, every time changing the output folder name.
·      SaveCustomersRx.jmx
·      GetCustomers.jmx
·      SaveCustomersRx
e)    Repeat step 6 (b), (c) and (d) for 10, 50, 100, 200 and 400 users.

Performance Metrics











Comments

Popular posts from this blog

SAAS Simple Maturity Model

There are two architectural models – commonly referred as SAAS Maturity models- that describe the transition of a service to what is called Multi-tenant efficient, highly scalable application. The SAAS Maturity model described by Microsoft has four distinct stages and is illustrated below. Another similar well-known model for SaaS-maturity is known as Forrester-model but adds another stage known as "Dynamic Business Apps-as-a-service". The three key Attributes of a SAAS Architecture: Configurability: Metadata used to configure the way the application behaves for customers Multi-tenant Efficiency : Maximizing the sharing of resources across tenants Scalability: Maximizing concurrency, resource efficiency SAAS Simple Maturity Model (Microsoft, 2006) SaaS Maturity Model (Forres...

What is an ESB?

ESB is another of these amorphous terms that means different things to different people. An ESB can be thought of as the next generation of Service Oriented Architecture. Everybody knows web services today, and they have been used extensively to allow companies to break the tyranny of proprietary architectures. Now you can wire applications to service providers without having to know or worry about the provider's underlying operating system or programming language. It is an architectural concept/construct - not a technology, despite some vendors (and even gartner) telling you otherwise. You'll find many different types of technology can fulfil the conceptual role of an ESB, hence be careful not to associate it with a particular technology. Therefore designing the architecture is more important than choosing a 'product'. An Enterprise Service Bus (ESB) is the "backbone" of the service-oriented architectural model which allows different protocols to be communica...

Web Service Framework comparison

Web Services is one of those concepts made all the more difficult to understand because of the myriad acronyms and abbreviations that are superfluous in any discussion. Covering all the concepts and standards associated with Web Services is a vast topic in itself. There are a large number of standards around Web Services. These standards define the norms of a Web Services implementation and ensure that a Web Services is accessed independently of the client platform. There are numerous frameworks available to select to build web service today. Below is the most widely used ones. Product Does it fit my need? Axis2.0 Apache Axis2 is a complete re-design and re-write of the widely used Apache Axis SOAP stack to build on the lessons learnt from Apache Axis. An advantage of Axis 2 is its support for the binding frameworks XMLBeans. Axis 2 with XMLBeans is widely ...