性能比较 - Spring Boot 应用程序中的线程池与虚拟线程 (Project Loom)

news2024/9/25 11:15:16

        本文比较了 Spring Boot 应用程序中的不同请求处理方法:ThreadPool、WebFlux、协程和虚拟线程 (Project Loom)。

        在本文中,我们将简要描述并粗略比较可在 Spring Boot 应用程序中使用的各种请求处理方法的性能。
        高效的请求处理在开发高性能后端应用程序中起着至关重要的作用。传统上,大多数开发人员使用 Spring Boot 应用程序中嵌入的 Tomcat,其默认线程池用于在后台处理请求。然而,替代方法近年来越来越受欢迎。WebFlux 利用事件循环进行响应式请求处理,而 Kotlin 协程及其suspend功能也越来越受到青睐。
        此外,引入虚拟线程的 Project Loom 预计将在 Java 21 中发布。不过,尽管 Java 21 尚未发布,但从 Java 19 开始我们就已经可以尝试 Project Loom 了。因此,在本文中,我们还将探索使用虚拟线程来处理请求。
        此外,我们将使用JMeter 进行高负载测试的不同请求处理方法进行性能比较。

性能测试模型

我们将使用以下模型来比较请求处理方法:

性能测试模型

流程就像蛋糕一样简单:

  • 客户端(JMeter)将并行发送 500 个请求。每个线程将等待响应,然后重复发送另一个请求。请求超时时间为 10 秒。测试时间将持续1分钟。
  • 我们正在测试的 Spring Boot 应用程序将接收来自客户端的请求并等待来自慢速服务器的响应。
  • 慢速服务器以随机超时响应。最大响应时间为 4 秒。平均响应时间为2秒。

处理的请求越多,性能结果就越好。

 

1. 线程池

默认情况下,Tomcat 使用线程池(有时称为连接池)来处理请求。
概念很简单:当请求到达 Tomcat 时,它会从线程池中分配一个线程来处理该请求。该分配的线程将保持阻塞状态,直到生成响应并将其发送回客户端。
默认情况下,线程池最多包含 200 个线程。这基本上意味着单个时间点只能处理 200 个请求。
但这个参数和其他参数是可配置的。

默认线程池

让我们对一个带有嵌入式 Tomcat 和默认线程池的简单 Spring Boot 应用程序进行性能测量。

线程池容纳 200 个线程。对于每个请求,服务器都会对另一台服务器进行阻塞调用,平均响应时间为两秒。因此我们可以预计每秒 100 个请求的吞吐量。

请求总数
吞吐量,请求/秒
响应时间,毫秒
错误率,%
平均的
最小
90%线
最大限度
3356
91.2
4787
155
6645
7304
0.00

值得注意的是,实际结果非常接近,测得的吞吐量为每秒 91.2 个请求。 

增加线程池 

让我们使用应用程序属性将线程池中的最大线程数增加到 400:

server:
  tomcat:
    threads:
      max: 400
 

让我们再次运行测试:

请求总数吞吐量,请求/秒响应时间,毫秒错误率,%
平均的最小90%线最大限度
6078176.7254910418448550.00

预计线程池中的线程数量加倍将使吞吐量提高两倍。

但请注意,在不考虑系统容量和资源限制的情况下增加线程池中的线程数量可能会对性能、稳定性和整体系统行为产生不利影响。根据系统的具体要求和功能仔细调整和优化线程池大小至关重要。

2.WebFlux

WebFlux 没有为每个请求分配专用线程,而是采用具有少量线程的事件循环模型,通常称为事件循环组。这使得它能够用有限数量的线程处理大量并发请求。请求是异步处理的,事件循环可以利用非阻塞 I/O 操作有效地同时处理多个请求。WebFlux非常适合需要高可扩展性的场景,例如处理大量长连接或流数据。
理想情况下,WebFlux 应用程序应该完全以响应式方式编写;有时,这并不那么容易。但我们有一个简单的应用程序,我们可以只使用WebClient 来调用慢速服务器。

@Bean
public WebClient slowServerClient() {
    return WebClient.builder()
            .baseUrl("http://127.0.0.1:8000")
            .build();
}

在 Spring WebFlux 的上下文中, RouterFunction 是请求映射和处理的另一种方法:

@Bean
public RouterFunction<ServerResponse> routes(WebClient slowServerClient) {
    return route(GET("/"), (ServerRequest req) -> ok()
            .body(slowServerClient
                  .get()
                  .exchangeToFlux(resp -> resp.bodyToFlux(Object.class)),
                  Object.class
            ));
}

但仍然可以使用传统控制器。

那么,让我们运行测试:

请求总数吞吐量,请求/秒响应时间,毫秒错误率,%
平均的最小90%线最大限度
7443219.2206812369943810.00

结果甚至比增加线程池的情况更好。但需要注意的是,线程池和 WebFlux 都有各自的优点和缺点,选择取决于具体要求、工作负载的性质以及开发团队的专业知识。

3. 协程和WebFlux

Kotlin协程 可以有效地用于请求处理,以更加并发和非阻塞的方式提供替代方法。
Spring WebFlux支持 协程来处理请求,所以让我们尝试编写这样一个控制器:

@GetMapping
suspend fun callSlowServer(): Flow<Any> {
    return slowServerClient.get().awaitExchange().bodyToFlow(String::class)
}

挂起函数可以执行长时间运行或阻塞操作,而不会阻塞底层线程。Kotlin 协程基础知识文章很好地描述了基础知识。

那么,让我们再次运行测试:

请求总数吞吐量,请求/秒响应时间,毫秒错误率,%
平均的最小90%线最大限度
7481220.420645361540490.00

粗略地,我们可以得出这样的结论:结果与没有协程的 WebFlux 应用程序的情况没有什么不同。

但除了协程之外,还使用了相同的WebFlux,测试可能并没有完全揭示出协程的潜力。下次,值得尝试Ktor。

4. 虚拟线程(Project Loom)

虚拟线程或纤维是Project Loom引入的概念。
与本机线程相比,虚拟线程的内存占用量显着降低,允许应用程序创建和管理更多数量的线程,而不会耗尽系统资源。它们可以更快地创建和切换,从而减少与线程创建相关的开销。
虚拟线程执行的切换由 Java 虚拟机 (JVM) 内部处理,可以在以下位置完成:
自愿挂起:虚拟线程可以使用Thread.sleep()或等方法显式挂起其执行CompletableFuture.await()。当虚拟线程自行挂起时,执行会暂时暂停,JVM 可以切换到执行另一个虚拟线程。
阻塞操作:当虚拟线程遇到阻塞操作,例如等待I/O或获取锁时,可以自动挂起。这允许 JVM 通过使用底层本机线程执行其他准备运行的虚拟线程来更有效地利用它们。
如果您对虚拟线程和载体线程主题感兴趣,请阅读 DZone 上这篇精彩的文章 — Java 虚拟线程 — 简单介绍。
虚拟线程最终将在 Java 21 中发布,但从 Java 19 开始我们就已经可以测试它们了。我们只需要显式指定 JVM 选项即可。

基本上,我们要做的就是用一些基于虚拟线程的执行器替换 Tomcat 线程池:

@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandler() {
    return protocolHandler ->
            protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
}

因此,我们开始使用虚拟线程,而不是线程池执行器。

让我们运行测试:

请求总数吞吐量,请求/秒响应时间,毫秒错误率,%
平均的最小90%线最大限度
7427219.3208012369340740.00

结果实际上与 WebFlux 的情况相同,但我们根本没有使用任何反应式技术。即使对于慢速服务器的调用,也使用常规阻塞 RestTemplate。我们所做的就是用虚拟线程执行器替换线程池。

结论

让我们将测试结果收集到一张表中:

请求处理程序
30 秒内的请求总数
吞吐量,请求/秒响应时间,毫秒错误率,%
平均的最小90%线最大限度
线程池(200 个线程)335691.24787155664573040.00
增加线程池(400 个线程)6078176.7254910418448550.00
WebFlux7443219.22068123699943810.00
WebFlux + 协程7481220.420645361540490.00
虚拟线程(Project Loom)7427219.3208012369340740.00

本文进行的性能测试比较肤浅,但我们可以得出一些初步结论:

  • 线程池表现出较差的性能结果。增加线程数量可能会带来改进,但应考虑系统的容量和资源限制。尽管如此,线程池仍然是一个可行的选择,特别是在处理大量阻塞操作时。
  • WebFlux 展示了非常好的结果。但值得注意的是,要充分受益于其性能。整个代码应该以响应式风格编写。 
  • 将协程与 WebFlux 结合使用会产生类似的性能结果。也许我们必须使用 Ktor 来尝试它们,Ktor 是一个专门为利用协程的力量而设计的框架。 
  • 使用虚拟线程(Project Loom)也产生了类似的结果。然而,值得注意的是,我们没有修改代码或采用任何反应技术。唯一的改变是用虚拟线程执行器替换线程池。尽管很简单,但与使用线程池相比,性能结果显着提高。 

因此,我们可以初步得出结论,Java 21中虚拟线程的发布将显着改变现有服务器和框架中请求处理的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/890055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Datawhale Django后端开发入门 Vscode TASK02 Admin管理员、外键的使用

一.Admin管理员的使用 1、启动django服务 使用创建管理员之前&#xff0c;一定要先启动django服务&#xff0c;虽然TASK01和TASK02是分开的&#xff0c;但是进行第二个流程的时候记得先启动django服务&#xff0c;注意此时是在你的项目文件夹下启动的&#xff0c;时刻注意要执…

安装Google cloud时出现错误如何解决

在安装Google cloud出现错误 找到这个路径下的文件&#xff0c;并将其删除。 C:\\Users\\Administrator\\AppData\\Roaming\\gcloud\\configurations\\config_default删除后&#xff0c;重新运行安装程序&#xff0c;问题解决&#xff01;&#xff01;&#xff01;

PyTorch训练简单的生成对抗网络GAN

文章目录 原理代码结果参考 原理 同时训练两个网络&#xff1a;辨别器Discriminator 和 生成器Generator Generator是 造假者&#xff0c;用来生成假数据。 Discriminator 是警察&#xff0c;尽可能的分辨出来哪些是造假的&#xff0c;哪些是真实的数据。 目的&#xff1a;使…

FreeRTOS qemu mps2-an385 bsp 移植制作 :系统运行篇

相关文章 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;环境搭建篇 FreeRTOS qemu mps2-an385 bsp 移植制作 &#xff1a;系统启动篇 开发环境 Win10 64位 VS Code&#xff0c;ssh 远程连接 ubuntu VMware Workstation Pro 16 Ubuntu 20.04 FreeRTOSv202212.01&a…

DataFrame.rename()函数--Pandas

1. 函数作用 修改DataFrame的行名、列名 2. 函数语法 DataFrame.rename(mapperNone, *, indexNone, columnsNone, axisNone, copyNone, inplaceFalse, levelNone, errorsignore)3. 函数参数 参数含义mapper与axis结合使用&#xff0c;表示运用到axis上的值&#xff1a;类字…

SRS流媒体服务(四)WebRTC实现实时视频通话和低延时互动直播

CentOS版本号&#xff1a;7.9 SRS版本号&#xff1a;4.0.215 服务器IP&#xff1a;192.168.5.104 注意需要开启端口号&#xff1a;1935、1985、8000&#xff08;UDP端口&#xff09;、8080。 注意需要开启服务&#xff1a;http 文章目录 webRTC介绍getUserMediaRTCPeerCon…

编译老版本c++程序 报错 msvcrt.dll 以及 0x000000 内存 不能为 “read“ 问题已解决

一般 win10 编译 xp对应老版本软件 调试采用 虚拟机形式进行测试&#xff0c;但是虚拟机中&#xff0c;无独立显卡&#xff0c;运行程序提示有&#xff0c;无法调用动态库&#xff0c;或者 内存无法读取&#xff0c;炸一看以为 winxp32位 内存识别只能3.7G.其实是显存无法使用…

【网工常用的CMD窗口命令行,你一定得记的】

作为网络工程师&#xff0c;工作中经常是容易被作为甩锅的对象。凡是业务系统出现问题或其他各种问题&#xff0c;人们总是会认为是网络问题&#xff0c;最初的怀疑都指向网工。然而最终结果往往是自己服务器出了问题。 现在我将列举几种我在日常工作中经常使用的查看网络状态…

七月 NFT 行业解读:游戏和音乐 NFT 引领增长,Opepen 掀起热潮

作者&#xff1a;lesleyfootprint.network 2023 年 7 月&#xff0c;NFT 市场的波动性持续存在&#xff0c;交易量呈下降趋势。然而&#xff0c;游戏和音乐 NFT 等领域的增长引人注目。参与这些细分领域的独立用户数量不断增加&#xff0c;反映了这些领域的复苏。 本综合报告…

实时会话简易版

1、数据存储 Redis缓存、pgsql数据库 2、存储使用 2.1、Redis缓存 1&#xff09;无序集合set&#xff1a;存储未读会话id 2&#xff09;list&#xff08;左进右出&#xff09;&#xff1a;存储会话未读消息 2.2、pgsql数据库 存储用户信息&#xff0c;存储会话id&#…

Maven之mirrorof范围

mirrorOf 是 central 还是 * 的问题 在配置阿里对官方中央仓库的镜像服务器时&#xff0c;我们使用到了 <mirror> 元素。 <mirror><id>aliyunmaven</id><mirrorOf>central</mirrorOf><name>阿里云公共仓库</name><url>…

【计算机视觉|生成对抗】非配对图像到图像的翻译:使用循环一致对抗网络(CycleGAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Unpaired Image-to-Image Translation Using Cycle-Consistent Adversarial Networks 链接&#xff1a;[1703.10593] Unpaired Image-to-Image Translation using Cycle-Consistent Adver…

基于metrics-server弹性伸缩

目录 Kubernetes部署方式 基于kubeadm部署K8S集群 一、环境准备 1.1、主机初始化配置 1.2、部署docker环境 二、部署kubernetes集群 2.1、组件介绍 2.2、配置阿里云yum源 2.3、安装kubelet kubeadm kubectl 2.4、配置init-config.yaml 2.5、安装master节点 2.6、安装…

2022年09月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;统计误差范围内的数 统计一个整数序列中与指定数字m误差范围小于等于X的数的个数。 时间限制&#xff1a;5000 内存限制&#xff1a;65536 输入 输入包含三行&#xff1a; 第一行为N&#xff0c;表示整数序列的长度(N < 100); 第二行为N个整数&#xff0c;…

在C中使用Socket实现多线程异步TCP消息发送

目录 基础知识开始实现主要函数说明结束语 在本篇文章中&#xff0c;我们会探讨如何在C语言中使用socket来实现多线程&#xff0c;异步发送TCP消息的系统。虽然C标准库并没有原生支持异步和多线程编程&#xff0c;但是我们可以结合使用POSIX线程&#xff08;pthread&#xff09…

React2023电商项目实战 - 1.项目搭建

古人学问无遗力&#xff0c;少壮工夫老始成。 纸上得来终觉浅&#xff0c;绝知此事要躬行。 —— 陆游《《冬夜读书示子聿》》 系列文章目录 项目搭建App登录及网关App文章自媒体平台&#xff08;博主后台&#xff09;内容审核(自动) 文章目录 系列文章目录一、项目介绍1.页面…

二维码网络钓鱼攻击泛滥!美国著名能源企业成主要攻击目标

近日&#xff0c;Cofense发现了一次专门针对美国能源公司的网络钓鱼攻击活动&#xff0c;攻击者利用二维码将恶意电子邮件塞进收件箱并绕过安全系统。 Cofense 方面表示&#xff0c;这是首次发现网络钓鱼行为者如此大规模的使用二维码进行钓鱼攻击&#xff0c;这表明他们可能正…

云计算——ACA学习 云计算核心技术

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 写在前面 本系列将会持续更新云计算阿里云ACA的学习&#xff0c;了解云计算及网络安全相关…

使用 AI 将绘画和照片转换为动画

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑器的3D应用场景 华盛顿大学和Facebook的研究人员最近发表了一篇论文&#xff0c;展示了一种基于深度学习的系统&#xff0c;可以将静止图像和绘画转换为动画。称为照片唤醒的算法使用卷积神经网络从单个静止图像以 …

性能分析之MySQL慢查询日志分析(慢查询日志)

一、背景 MySQL的慢查询日志是MySQL提供的一种日志记录,他用来记录在MySQL中响应的时间超过阈值的语句,具体指运行时间超过long_query_time(默认是10秒)值的SQL,会被记录到慢查询日志中。 慢查询日志一般用于性能分析时开启,收集慢SQL然后通过explain进行全面分析,一…