spring boot中虚拟线程性能探讨
Spring Boot 已成为 Java 生态系统中事实上的框架。在这篇文章中,让我们讨论如何在 Spring Boot 应用程序中配置虚拟线程,并研究和比较其与本机线程的性能特征。
此 Spring Boot 应用程序将使用 REST 端点计算大于或等于 10000 的常数的斐波那契和。借助 JMeter,我们将模拟 30 分钟内 1000 个用户的负载,并了解其吞吐量和偏差。我们将针对本机线程和虚拟线程执行此实验,并分析这些操作的线程转储和 GC 日志分析。
斐波那契和
让我们开发一个小代码来计算 10000 的斐波那契和(我们可以更改该值)。以下代码将计算 10000 的斐波那契和并返回该值。
注意: 计算更高值的斐波那契和需要大量的 CPU 能力。
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;}
开发 Rest 控制器
接下来,我们将开发一个 REST 控制器,添加一个 GET 端点并挂接到斐波那契总和,然后返回总和。看一下调用 fibonacciSum() 方法的 fib() 方法。
@RestControllerpublic class TestController {@GetMapping("/fib")public long fib() {return fibonacciSum();}}
使用虚拟线程对 1000 个用户进行测试
我们将使用JMeter模拟 1000 个用户的负载,持续约 1800 秒(30 分钟) 。这是为了了解应用程序在不同线程场景下的负载下的表现。
首先,我们将执行虚拟线程的负载测试。因此,我们需要启动启用虚拟线程的 Spring Boot 应用程序来执行负载测试。
当我们使用 JMeter 将 1000 个用户的负载应用到我们的应用程序时,您可以在 JMeter 工具的 HTTP 请求采样器的图形结果部分看到一些变化。这些是处理请求时的吞吐量、偏差和平均值的图形表示。
图 1:带有虚拟线程 JMeter 负载测试的 SpringBoot
分析JMeter图表结果
您在上图中看到了什么?此图显示了支持虚拟线程的 Spring Boot 应用程序的一些指标。
有红线、蓝线、黄线和绿线。红线显示偏差,值为 12773。 此值显示响应时间在平均值附近变化的程度。吞吐量是每分钟可以处理的请求数。在本例中为每分钟10,778.003个请求。以绿色表示。蓝线显示处理一组请求样本所需的平均时间。在本例中为5356 毫秒。
接下来,我们将使用原生线程对 Spring Boot 进行负载测试。
图 2:使用 Native Threads JMeter 进行 SpringBoot 负载测试
我们先来看看应用程序的吞吐量。它是每分钟 10,125.924 。与虚拟线程相比,没有太大区别。下一个属性是偏差,在本例中为 20868。 如果与虚拟线程进行比较,这个值并不好。应用程序的平均时间为5684毫秒
让我们以表格形式总结一下我们的理解:
吞吐量 | 偏差 | 平均(毫秒) | |
---|---|---|---|
本机线程 | 10,125.924 | 20868 | 5684 |
虚拟线程 | 10,778.003 | 12773 | 5356 |
您可以在此处看到,使用虚拟线程的 Spring Boot 应用程序与本机线程版本的吞吐量没有太大差异。这是因为执行的代码是 CPU 密集型操作。因此,在这种情况下,虚拟线程不会从此应用程序中获得太多好处。当执行内存密集型操作时,虚拟线程会大放异彩。
我们将更深入地探讨这一说法。在我们的负载测试中,当我们将具有本机线程的 SpringBoot 应用程序的负载增加到 10000 个用户时会发生什么?应用程序很可能会抛出 OutOfMemoryError。但在具有虚拟线程的应用程序的情况下,这种情况可能不会发生得这么快。
但是虚拟线程有一个优点。在这种情况下,JVM 不会创建 1000 个线程。它只需要非常少量的线程。这就是我们将在下一节中使用fastthread 工具集进行线程转储分析时揭示的内容。
线程性能
在进行上述两个测试时,我们捕获了线程转储并通过线程转储分析网站对其进行了分析。
您可以在此处找到本机线程的线程转储分析报告。从分析报告中,您可以看到该应用程序正在使用 235 个线程。正如预期的那样,对于一个非常小的测试应用程序来说,这个值相当高。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
图 3:具有本机线程的应用程序的线程转储分析
现在我们来看看带有虚拟线程的线程转储分析报告。
图 4:具有虚拟线程的应用程序的线程转储分析
这里,总线程数为 43,与本机版本相比,这个值非常低。这是虚拟线程的优势之一。也就是说,通过消耗更少的线程数,可以实现相同的吞吐量。
结论
在本文中,我们分析了使用 SpringBoot 应用程序的虚拟线程和本机线程的优缺点。在此示例中,我们在 GET 请求中使用 CPU 密集型代码,该代码将计算 10000 以内的斐波那契和。我们看到,在这个应用程序中,虚拟线程相对于本机线程没有任何优势。