Some days ago we did an optimized version of our series with Spring Web, now we will try to improve further the numbers using a reactive platform, for this we will use Spring WebFlux and R2DBC.
Here, as a reference, are the numbers that we got so far :
C. Users
Pods
ART
TPS
Max CPU
Max MEM
Service
1
1
39.16
25.49
403
474
01 Base
1
1
34.61
28.85
209
252
02 Spring Web
10
1
570.47
16.73
916
487
01 Base
10
1
111.61
85.53
626
350
02 Spring Web
25
3
1615.82
14.72
1049
1454
01 Base
25
1
266.03
89.44
686
369
02 Spring Web
50
5
3190.98
14.89
1351
2499
01 Base
50
3
1982.03
23.95
774
1060
02 Spring Web
01 Base = Java 8 - Spring Boot 2.2.2 - Spring Web - Spring Data JDBC default settings, unoptimized 02 Spring Web = Java 11 - Spring Boot 2.2.2 - Spring Web - Spring Data JDBC optimized
Bootstrapping a Spring Boot application
We are going to use Spring Initializr https://start.spring.io/ to quickly bootstrap our application.
We will create a Maven Project using Java 1 and Spring Boot version 2.2.4, we will set the Group to be org.learning.by.example.movies, and the Artifact to spring-webflux, the rest of the values should be automatically populated.
For dependencies we will search and add :
Spring Reactive Web
Spring Data R2DBC [Experimental]
PostgreSQL Driver
Spring Boot Actuator
Now we will click on Generate to download our zip file : spring-webflux.zip, we will uncompress it and leave it ready to be opened with our favorite IDE.
Creating a Reactive repository
First we will create our POJO that we will use to retrive a movie.
This is identical as we did in our JDBC example.
Now we will create our reactive repository.
This is very similar of the JDBC repository that we create before.
Now we need to create a converter.
This is doing almost what our mapper was doing for JDBC.
Next we will need to create a ConfigurationProperties to have our database configuration.
This is very similar to our JDBC example however we are not use a JDBC string so will be set the host, port and database in separate variables.
Finally we will setup our data base configuration.
This is how setup a connection to our database with a connection pool and set our converter.
Creating our Routes
We wil continue creating our router
As we could see this is a simple RouterFunction for our /movies/genre URL.
Next will be the handler.
The handler is using the repository to retrieve the movies and return the response back to the router.
Finally we will setup our configuration in our application.yml
Configuring our deployment
First we will copy our Dockerfile, deployment.yml, JMeter scripts and bash scripts for our previous example and rename movies-spring-web to movies-spring-webflux on them.
Them we will modify our deployment.yml
We are setting up additional JAVA_OPTS that are require to use native buffers in Netty on Java 9+.
Them we will edit our jlink.sh script to include an additional module :
Finally we could build and deploy our application :
Running the complete set
With this we are ready to run our final test following the procedure that we stablish in the first part of the series, and we will get this numbers :
C. Users
Pods
ART
TPS
Max CPU
Max MEM
Service
1
1
39.16
25.49
403
474
01 Base
1
1
34.61
28.85
209
252
02 Spring Web
1
1
31.21
31.99
335
310
03 Spring WebFlux
10
1
570.47
16.73
916
487
01 Base
10
1
111.61
85.53
350
626
02 Spring Web
10
1
100.93
94.59
1036
355
03 Spring WebFlux
25
3
1615.82
14.72
1049
1454
01 Base
25
1
266.03
89.44
686
369
02 Spring Web
25
1
368.0
76.33
1046
511
03 Spring WebFlux
50
5
3190.98
14.89
1351
2499
01 Base
50
3
1982.03
23.95
774
1060
02 Spring Web
50
1
631.65
75.24
1063
515
03 Spring WebFlux
01 Base = Java 8 - Spring Boot 2.2.2 - Spring Web - Spring Data JDBC default settings, unoptimized 02 Spring Web = Java 11 - Spring Boot 2.2.2 - Spring Web - Spring Data JDBC optimized 03 Spring WebFlux = Java 11 - Spring Boot 2.2.4 - Spring WebFlux - Spring Data R2DBC optimized
Conclusions
As we could see the performance of the reactive solution is great, we could even handle 50 concurrent users with just one Pod, and that is because we are not so bound to threads in this implementation.
However we could see that with 25 concurrent users we are not doing so great, and that is probably because we setup very a very small heap and the GC is cleaning more often that it should, but I’ve setup this to minimize memory consumption, we could increase a bit the heap this will cause less GC runs, better ART but more MEM usage, and this is key in our overall optimization strategy, if we care more about ART of use of MEM.
Finally, Spring Data R2DBC still on experimental stage, numbers will change with future relases.
Note: The full code of this service is available at this repository.