Virtual Threads Performance in Spring Boot

Spring Boot has become the de facto framework in the Java ecosystem. In this post, let’s discuss how to configure Virtual Threads in a Spring Boot Application and study and compare its performance characteristics with native threads.

This Spring Boot application is going to calculate the fibonacci sum for a constant number which is greater than or equal to 10000 by using  a REST endpoint. With the help of JMeter, we will simulate a load of 1000 users for 30 minutes and understand its throughput and deviations. We are going to perform this experiment for native threads and virtual threads and analyze the thread dump and GC log analysis for these operations.

Fibonacci Sum

Let’s develop a small code that is going to calculate the fibonacci sum for 10000 (we can change the value). The following code will calculate the fibonacci sum to 10000 and will return the value.

Note: Calculating fibonacci sum for a higher value requires a lot of CPU power.

private long fibonacciSum() {

int number = 10000;

long sum = 2;

int fibo1 = 1, fibo2 = 1, fibonacci = 1;

for (int i = 3; i <= number; i++) {

fibonacci = fibo1 + fibo2;

fibo1 = fibo2;

fibo2 = fibonacci;

sum = sum + fibonacci;

}

return sum;

}

Develop a Rest Controller

Next, we are going to develop a REST controller and add a GET endpoint and hook to the fibonacci sum and will return the sum. Take a look at the fib() method that invokes  fibonacciSum() method.

@RestController

public class TestController {

@GetMapping("/fib")

public long fib() {

return fibonacciSum();

}

}

Test for 1000 users using virtual threads

We are going to simulate the load for 1000 users for about 1800 seconds(30 minutes) using JMeter. This is to understand how the application is going to behave under the load for different thread scenarios.

 First we will perform the load test for virtual threads. So, we need to start the Spring Boot application with virtual threads enabled to perform the load test.

When we apply a load for 1000 users to our application using JMeter, you can see something happens in the graphical results section of the HTTP Request Sampler of JMeter tool. These are the graphical representation of throughput, deviation and average while handling the requests.

SpringBoot with Virtual Threads JMeter load test
Fig 1: SpringBoot with Virtual Threads JMeter load test

Analyze the JMeter graph results

What do you see in the above graph? This graph displays a few metrics for the Spring Boot application that supports virtual thread. 

There are red, blue, yellow and green lines. The red lines show the deviation and the value is 12773. This value shows how much the response time varies around the average. The throughput is the number of requests it can process per minute. In this case it is 10,778.003 per minute.This is represented in green color. The blue line shows the average time it takes to process a set sample of requests. In this case it is 5356 milliseconds.

Next, we will perform the load test for Spring Boot with native threads.

SpringBoot with Native Threads JMeter load test
Fig 2: SpringBoot with Native Threads JMeter load test

Let’s first take a look at the throughput of the application. It is 10,125.924 per minute. As compared to the virtual threads, there is not much difference. The next attribute is deviation which in this case is 20868. This value, if you compare it with a virtual thread, is not better. The average of the application is 5684 milliseconds

Let’s summarize our understanding in a tabular form:

ThroughputDeviationAverage (ms)
Native Thread10,125.924208685684
Virtual Thread10,778.003127735356

You can see here that there is not much difference in the throughput of the Spring Boot application with virtual threads against native thread version. This is because the code that executes is a CPU intensive operation. So, in this case virtual thread will not get much benefit from this application. The virtual threads shine when a memory intensive operation is performed.

We will explore this statement a little bit deeper. In our load test, what happens when we increase the load to 10000 users for the SpringBoot application with native threads? It is likely that the application may throw OutOfMemoryError. But in the case of applications with virtual threads, this may not happen so quickly.  

 But there is one advantage in the case of virtual threads. The JVM will not create 1000 threads in this case. It only requires a very small amount of threads. This is what we are going to reveal in our thread dump analysis using the fastthread toolset in the next section.

Threads Performance

When we conducted the above two tests, we captured thread dumps and analyzed them through a thread dump analysis website.

You can find the thread dump analysis report of the native threads here. From the analysis report, you can see that the application is using 235 threads.As expected, this value is quite high for a very small test application.

Thread dump analysis for application with native threads
Fig 3: Thread dump analysis for application with native threads

Now we will take a look at the thread dump analysis report with virtual threads.

Thread dump analysis for application with virtual threads
Fig 4: Thread dump analysis for application with virtual threads

Here, the total thread count is 43 and this value is very low as compared to the native version. This is one of the advantages of virtual threads.  I.e. by consuming less number of threads same throughput can be achieved.

Conclusion

In this article, we have analyzed the pros and cons of virtual thread and native threads using a SpringBoot application.In this example, we are using a CPU intensive code in a GET request that will calculate the fibonacci sum for numbers to 10000. We saw that the virtual threads do not have any advantages over native threads in this application.

Share your Thoughts!

Up ↑

Discover more from yCrash

Subscribe now to keep reading and get access to the full archive.

Continue reading