SpringBoot virtual threads vs webflux: Performance comparison for JWT verify and MySQL query

Mayank Choubey
Tech Tonic
5 min readSep 4, 2023

--

Introduction

Following a prolific run of articles assessing the performance of a range of technologies, including Node.js, Deno, Bun, Rust, Go, Spring, Python, and more in the context of a simple “hello world” scenario, I received consistent feedback. While these articles garnered praise, there was a common refrain: they didn’t directly address real-world use cases. Readers urged me to extend the analysis to encompass more practical scenarios. Remarkably, these articles continued to draw a substantial number of views. Nevertheless, the point was well-founded. As a starting point, “hello world” is ideal, but it falls significantly short of representing real-world complexities.

Real-world use case

This article is a segment of our ongoing series aimed at dissecting various technologies through the lens of real-world scenarios. In this particular case, we’re delving into the following common use case:

1. Extract a JWT from the authorization header.
2. Validate the JWT and extract the user’s email from its claims.
3. Execute a MySQL query using the extracted email.
4. Finally, return the user’s record.

While this scenario may seem straightforward, it encapsulates a frequently encountered real-world challenge in the realm of web development.

Technologies

In this article, we’ll dive into a friendly comparison between siblings, SpringBoot with virtual threads and Webflux, focusing on their performance in a specific use-case scenario. We’ve already explored how a standard SpringBoot application stacks up against webflux, but now, we introduce a crucial differentiator:

Spring Boot with Virtual Threads

We have SpringBoot, but with a twist — it’s running on virtual threads instead of traditional physical threads. Virtual threads are a game-changer in the realm of concurrency. These lightweight threads simplify the often complex task of developing, maintaining, and debugging high-throughput concurrent applications. While virtual threads still operate on underlying OS threads, they introduce a remarkable efficiency improvement. When a virtual thread encounters a blocking I/O operation, the Java runtime temporarily suspends it, freeing up the associated OS thread to serve other virtual threads. This elegant solution optimizes resource allocation and enhances overall application responsiveness.

SpringBoot Webflux

On the other side of the ring, we have Spring Boot Webflux. Spring Boot WebFlux is a reactive programming framework within the Spring ecosystem, designed to build highly scalable and asynchronous web applications. It leverages the Project Reactor library to enable non-blocking, event-driven programming. Spring Boot WebFlux is particularly well-suited for applications that require high concurrency and low latency, making it an excellent choice for building reactive microservices and real-time, data-intensive applications. With its reactive approach, it allows developers to efficiently handle a large number of concurrent requests while still providing the flexibility to integrate with various data sources and communication protocols.

With these intriguing setups in mind, let’s delve deeper into our performance comparison.

Testing Environment and Software Versions

Our performance tests were conducted on a MacBook Pro M1 equipped with 16GB of RAM, ensuring a reliable testing platform. The software stack utilized for these tests includes:

  • SpringBoot 3.1.3 (Running on Java 20)
  • Preview mode enabled to get the power of virtual threads

SpringBoot and Supporting Libraries

Our setup involved the use of the following key components:

- SpringBoot 3.1.3 with Java 20 (preview mode to get VT)
- jjwt for JWT verification and decoding, enhancing the security of our application.
- mysql-connector-java for performing MySQL queries, maintaining data integrity and consistency.

Load Testing and JWTs

To evaluate the performance of our applications under varying loads, we employed the open-source load testing tool, Bombardier. Our test scenario involved a pre-created list of 100,000 JWTs. During testing, Bombardier randomly selected JWTs from this pool and included them in the Authorization header of the HTTP requests.

MySQL Database Schema

The MySQL database used for these performance tests featured a table named users. This table was designed with 6 columns, good enough to simulate real-world data interactions within our applications, enabling us to assess their responsiveness and scalability.

mysql> desc users;
+--------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| email | varchar(255) | NO | PRI | NULL | |
| first | varchar(255) | YES | | NULL | |
| last | varchar(255) | YES | | NULL | |
| city | varchar(255) | YES | | NULL | |
| county | varchar(255) | YES | | NULL | |
| age | int | YES | | NULL | |
+--------+--------------+------+-----+---------+-------+
6 rows in set (0.00 sec)

The user database has been primed with an initial dataset containing a substantial 100,000 user records.

mysql> select count(*) from users;
+----------+
| count(*) |
+----------+
| 99999 |
+----------+
1 row in set (0.01 sec)

In the context of our friendly performance evaluation between SpringBoot virtual threads and Webflux, it’s essential to understand a crucial data relationship. Specifically, within the JSON Web Token (JWT) payload, each email entry corresponds directly to a user record stored in our MySQL database.

Code

SpringBoot (virtual threads)

SpringBoot Webflux

Results

In our quest to assess the performance, we conducted a rigorous series of tests. Each test consisted of a staggering 5 million requests, and we assessed their performance under varying levels of concurrent connections: 50, 100, and 300.

Now, let’s dive into the results, presented in a compact tabular format:

Conclusion

A scorecard is generated from the results using the following formula. For each measurement, get the winning margin. If the winning margin is:

  • < 5%, no points are given
  • between 5% and 20%, 1 point is given to the winner
  • between 20% and 50%, 2 points are given to the winner
  • > 50%, 3 points are given to the winner

It doesn’t look like that we’re getting any benefits of using virtual threads over webflux even for real-world cases like this one. If you like to share, please add your expert opinion about virtual threads in the comments.

A list of all real-world performance comparisons is here.

--

--