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

Mayank Choubey
Tech Tonic
5 min readSep 14, 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 all the siblings, SpringBoot with physical threads, 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.

With these intriguing setups in mind, let’s delve deeper into our performance comparison. This article is being written to address one of the most common requests to see a comparison of physical vs virtual vs webflux for real-world use cases.

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
  • 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 physical threads vs virtual threads vs 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 (physical threads)

Springboot (virtual threads)

SpringBoot (webflux)

Results

In our quest to assess the performance, we conducted a rigorous series of tests. Each test consisted of 1 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 chart format:

Analysis

In this setup, i.e. with the MySQL driver, the virtual threads offer the lowest of the performance. Webflux stays way ahead.

We understand that this MySQL driver is not virtual thread friendly. Please suggest the best driver that we should use for the virtual threads. We’ll update the article as soon we see different results.

Thanks for reading!

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

--

--