SpringBoot2 Blocking Web vs Reactive Web

Hello, I’m Mitz. This is the first post on dev.to. Nice to meet you 🙂

Buzzwords into my ToolBox

As many of you’ve heard Microservices, Blockchain, etc, there’re a variety of tech buzzwords and they come and go often. Therefore, it’s important for us not to believe them without even checking, but to see for ourselves how they work then put them into our toolbox. That’s why I tried using a part of Reactive Programming this time.

One of the benefit of Reactive Programming is that we can use machine resources effectively. For example, in case of a web application, a server can handle more requests than blocking style application with less threads.

SpringBoot2 Reactive Web

SpringBoot2, which was released at the beginning of this month, has introduced “Reactive Web” feature. So I tried comparing “Spring Web” and “Spring Reactive Web”. “Spring Web” is based on a conventional blocking style with Servlet, and “Spring Reactive Web” is a new style with reactive programming.

图片[1]-SpringBoot2 Blocking Web vs Reactive Web - 拾光赋-拾光赋
(Image from https://spring.io/ )

Demo Apps Architecture

I found a great article which compares SpringBoot1 and SpringBoot2:
Raw Performance Numbers – Spring Boot 2 Webflux vs. Spring Boot 1.
I did almost the same thing to compare SpringBoot2 Blocking Web vs Reactive Web. The architecture is like this:

There’re 3 apps:

  • delay-service
  • blocking-app
  • reactive-app

The source code is here:
https://github.com/bufferings/webflux-demo-201803

delay-service

The delay-service emulates an outside API with some latency. We can set the latency with a path parameter:

  @GetMapping("/{delayMillis}")
  public Mono<String> get(@PathVariable int delayMillis) {
    return Mono.just("OK")
        .delayElement(Duration.ofMillis(delayMillis));
  }

Enter fullscreen mode Exit fullscreen mode

blocking-app

The blocking-app is a simple Spring Web app, which calls delay-service in a blocking manner and returns it with a blocking manner:

  private static final String DELAY_SERVICE_URL = "http://localhost:8080";

  private final RestTemplate client;

  public BlockingApp(RestTemplateBuilder builder) {
    client = builder.rootUri(DELAY_SERVICE_URL).build();
  }

  @GetMapping("/{delayMillis}")
  public String get(@PathVariable String delayMillis) {
    String result = client.getForObject("/" + delayMillis, String.class);
    return "Blocking:" + result;
  }

Enter fullscreen mode Exit fullscreen mode

reactive-app

The reactive-app is a Spring Web Reactive app, which calls delay-service with a reactive client and returns Mono:

  private static final String DELAY_SERVICE_URL = "http://localhost:8080";

  private final WebClient client = WebClient.create(DELAY_SERVICE_URL);

  @GetMapping("/{delayMillis}")
  public Mono<String> get(@PathVariable String delayMillis) {
    return client.get()
        .uri("/" + delayMillis)
        .retrieve()
        .bodyToMono(String.class)
        .map(s -> "Reactive:" + s);
  }

Enter fullscreen mode Exit fullscreen mode

Let’s check the performance!

Start delay-service:

./gradlew -p apps/delay-service clean bootRun

curl -w "\n%{time_total}s\n" localhost:8080/1000
# returns "OK" after 1000ms

curl -w "\n%{time_total}s\n" localhost:8080/2000
# returns "OK" after 2000ms

Enter fullscreen mode Exit fullscreen mode

Start blocking-app:

./gradlew -p apps/blocking-app clean bootRun

curl -w "\n%{time_total}s\n" localhost:8081/2000
# returns "Blocking:OK" after 2000ms

Enter fullscreen mode Exit fullscreen mode

Start reactive-app:

./gradlew -p apps/reactive-app clean bootRun

curl -w "\n%{time_total}s\n" localhost:8082/2000
# returns "Reactive:OK" after 2000ms

Enter fullscreen mode Exit fullscreen mode

Now, all three apps are running.

Load Test Scenario

I used Gatling(https://gatling.io/) for the load test.

The scenario is something like this “1000 users call the API 30 times with 1 to 2 sec intervals”. I would like to set the latency of delay-service as 300ms.

  val myScenario = scenario("Webflux Demo").exec(
    repeat(30) {
      exec(
        http("request_1").get(targetUrl)
      ).pause(1 second, 2 seconds)
    }
  )
  setUp(myScenario.inject(rampUsers(simUsers).over(30 seconds)))

Enter fullscreen mode Exit fullscreen mode

Gatling to blocking-app

./gradlew -p apps/load-test -DTARGET_URL=http://localhost:8081/300 \
    -DSIM_USERS=1000 gatlingRun

Enter fullscreen mode Exit fullscreen mode

With VisualVM, we can see the worker threads count increase up to 200 which is the default maxThread value of the Tomcat.

Gatling to reactive-app

./gradlew -p apps/load-test -DTARGET_URL=http://localhost:8082/300 \
    -DSIM_USERS=1000 gatlingRun

Enter fullscreen mode Exit fullscreen mode

It only use 4 threads to handle the request.

Load Test Result

Here’s the result.

As you can see, for 1000 users both apps work nicely with around 300ms response time as we expected. But for 3000 & 6000 users, the 95 percentile of blocking-app becomes worse.

On the other hand, reactive-app keeps the good response speed around 400ms and it shows about 2000rps with my laptop(Core i7-7500U 2.7GHz/16GB RAM).

Interesting result!

blocking-app

with 1000 users:

with 3000 users:

with 6000 users:

reactive-app

with 1000 users:

with 3000 users:

with 6000 users:

What’s left

Increasing Tomcat maxThreads

Since I decided to try with the default config, the Tomcat threads count reached to 200 which is the default value of maxThreads. Probably tuning maxThread would improve the blocking-app performance.

Separating the env

Since I tried this demo all in my laptop, all the apps affected each other regarding the resource usage. So separating each apps into several machine might show different result.

Conclusion

In conclusion, we could know how SpringBoot2 Reactive Web handles requests efficiently. But I recommend you to check it by yourself. Especially Reactive Web style programming requires Java engineer to change their mindset to some extent I think.

Anyway, it’s so interesting and I’m feeling now SpringBoot2 Reactive Web is in my toolbox. Thank you!

原文链接:SpringBoot2 Blocking Web vs Reactive Web

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
Don’t worry about what others are doing better than you. Concentrate on beating your own records every day.
不要担心别人会做得比你好。你只需要每天都做得比前一天好就可以了
评论 抢沙发

请登录后发表评论

    暂无评论内容