Performance Comparison - RSocket Vs Webflux
Background
In one of my previous post we saw tangible advantages (w.r.t throughput, latency and resource utilization) of refactoring existing Microservice application from imperative to reactive constructs.
So an obvious question that comes to an inquisitive mind -
Can we apply Reactive principles to the underlying communication layer
Answer to above question is - Yes and RSocket is the way to go
What is RSocket
RSocket is a binary protocol that can perform bi-directional communication via TCP. RSocket tries to overcome few of the limitations of HTTP1 and HTTP2 by providing following features -
- Back-Pressure
- Multiplexing
- Resumption
- Routing
It has been developed to match the semantics of Reactive Streams. Hence it seamlessly integrates with Project Reactor and ReactiveX
It mainly supports 4 communication models :
- Fire and Forget (No Response)
- Request Response (Single Response)
- Request Stream (Multiple Responses)
- Channel (Bi-directional Response)
Lets try to understand Request-Response model with a working example along with performance comparison w.r.t Spring Webflux APIs
Bird's eye view of demo example
Working example (along with its source code) which we will be using for demonstration, primarily consists of 2 simple Spring Boot applications -
- Card Client - Public facing edge application with below endpoints. It uses WebClient to invoke downstream system's APIs and and RSocket client to communicate with downstream system's destination based on declared pattern.
1 @GetMapping("/rsocket/card/{cardId}")
2 public Mono<CardEntity> cardByIdWithRSocket(@PathVariable String cardId) {
3 log.info("Entering CardClientController : cardByIdWithRSocket with path variable as {} ", cardId);
4 Mono<CardEntity> cardEntityMono = rSocket
5 .route("rsocket-find-specific")
6 .data(cardId)
7 .retrieveMono(CardEntity.class);
8
9 log.info("Card details received");
10 return cardEntityMono;
11 }
APIs exposed by application
HTTP Method | URI | Description |
---|---|---|
GET | rx/card/{id} | Fetches a card based on cardId by using WebClient |
GET | rsocket/card/{id} | Fetches a card based on cardId by using RSocket |
- Card Service - Application which not only exposes Webflux endpoint but also has a connection point for accepting RSocket client connection via @MessageMapping. It will be using Redis as a persistent store. It also has a bulk loader which will load 5000 cards into the database whenever it bootstraps.
1 @MessageMapping("rsocket-find-specific")
2 public Mono<CardEntity> rSocketFindSpecific(String cardId) {
3 log.info("Entering CardViewController : rSocketFindSpecific with cardId : {} ", cardId);
4 return cardService
5 .getCardById(cardId)
6 //.delayElement(Duration.ofSeconds(1))
7 .doFinally(sig -> log.info("Response sent"));
8 }
Comparison based on performance metrics
Lets try to comparatively analyze RSocket Vs Webflux from performance standpoint. We will be using Gatling to simulate a load test.
Throughput & Latency
Above reports clearly shows that -
- 95th Percentile response time of RSocket based communication is 1/3 of Webflux based API consumption
- Mean response time of RSocket based communication is 1/2 of Webflux based API consumption
- Failures in RSocket based communication is 1/2 of WebFlux based API consumption
- TPS for successful requests in RSocket based communication is twice more than that of Webflux based API consumption
JVM Memory usage and Garbage Collection behavior
GC logging was enabled while performing load testing. GC logs were parsed via GC Easy to infer detailed JVM heap and GC behavior. Below are the observations w.r.t key performance parameters :
GC Pause Time
Time taken by single Stop the World (STW) GC
Object Promotion Metrics
Metrics indicating size and rate at which objects are promoted from Young Generation to Old Generation. Higher the promotion rate, higher the frequency of full GCs i.e. STW GC
GC Throughput
Percentage of time spent in performing business transaction against time spent in GC activity
Reference - One may want to refer my old article to understand nuances of Garbage Collection
Conclusion
As we saw in this article that along with obvious motivations behind using RSocket, there are compelling performance reasons which may incline us to leverage this protocol in justifiable way for inter service communication.
comments powered by Disqus