SpringBoot MVC vs Webflux: Performance comparison for JWT verify and MySQL query

Mayank C
Tech Tonic

--

Introduction

After publishing a record number of articles on comparing performance of various technologies like Node.js, Deno, Bun, Rust, Go, Spring, Python, etc. for a simple hello world case, I consistently got comments that the articles were good, but weren’t applicable directly for real-world use cases. I was asked to do the same for more ‘real-world’ cases. The articles also (and still) attracted a record number of views. However, the point was well taken. Hello world was the best starting point, but definitely not a ‘real-world’ case.

Real-world use case

With this article, I’m starting a new series where I’m going to compare a number of technologies for a real-world case:

  • Get JWT from the authorization header
  • Verify JWT & get email from claims
  • Perform a MySQL query with email
  • Return the user record

This is a very common real-world case. For the ‘Hello world’ case, I’ve seen the technologies offering somewhere between 70K to 200K RPS. The RPS was high because all the app was doing was returning a simple string. Of course, we won’t expect a 50–100K RPS for the JWT + MySQL use case. How much we’ll get is yet to be seen.

This article compares SpringBoot MVC & Webflux for this use-case. This is an interesting comparison because they are sister technologies. The only difference is that, Webflux uses reactive programming. A healthy competition within the family!

Due to the large number of articles that will get published, I’ll also be creating an article to index all the real-world cases. At the end of this article, you’ll find a link to that article. Let’s get started.

Test setup

All tests are executed on MacBook Pro M1 with 16G of RAM.

The software versions are:

  • SpringBoot v3.1.0 over Java 20

I’m using jjwt for verifying and decoding JWTs. I’m also using mysql-connector-java for performing MySQL queries.

The HTTP load tester is built over libcurl. There is a pre-created list of 100K JWTs. The tester picks random JWTs and sends it in the Authorization header of the HTTP request.

The MySQL database contains a table called users, which has 6 columns:

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 users table is prepopulated with 100K records:

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

For each email present in the JWT, there is a corresponding user record in the MySQL database.

Code

SpringBoot

SpringBoot Webflux

Results

Each test is executed for 1M requests in total. The concurrency levels are 10, 50, and 100 connections. A warm-up of 1K requests is given before taking measurements.

Here are the charts with the results:

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

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

--

--