第十七章. 性能调优番外篇:Web 容器选型与 JMeter 压测实战
第十七章. 性能调优番外篇:Web 容器选型与 JMeter 压测实战
Prorise第十七章. 性能调优番外篇:Web 容器选型与 JMeter 压测实战
摘要:本章将跳出代码层面,聚焦应用的运行环境。我们将对比 Tomcat 与 Undertow 的性能差异,解析 RVP 选择 Undertow 的底层逻辑,并详解其核心参数配置。
在之前的章节中,我们深入探讨了 RVP 框架的代码架构、工具封装以及并发编程。现在,我们把视线拉高,关注应用程序的运行载体——Web 容器。
Spring Boot 的一大优势是内置了 Web 容器,使我们能够以 JAR 包形式直接运行服务。默认情况下,Spring Boot 使用 Tomcat。但在 RVP 框架中,我们选择了 Undertow。
本章,我们将通过客观的性能数据对比,揭示 RVP 做出这一选择的原因,并学习如何针对 Undertow 进行参数调优。
17.1. Web 容器选型:Tomcat vs Undertow
在传统的 Java Web 开发中,我们通常将应用打包成 WAR 包,部署到独立的 Tomcat 服务器中。Spring Boot 改变了这一模式,它支持将容器(Tomcat, Jetty, Undertow)嵌入到应用内部。
17.1.1. 容器演进与选择
目前 Spring Boot 支持的三大主流容器:
- Tomcat:Apache 基金会顶级项目,历史悠久,生态最完善,是 Spring Boot 的默认选择。但在高并发场景下,其吞吐量和内存占用往往不是最优解。
- Jetty:以轻量级著称,长连接(如 WebSocket)支持较好,启动速度快。
- Undertow:Red Hat 开源的非阻塞 Web 服务器。它基于 NIO,以架构简单、高性能、低内存占用而闻名。
17.1.2. 性能对比数据分析
为了量化差异,我们基于相同的硬件环境(模拟 100、500、1000 并发线程)对这三者进行了压测。以下是基于 JMeter 聚合报告的核心数据对比:
| 指标 | Tomcat | Jetty | Undertow | 结论 |
|---|---|---|---|---|
| 吞吐量 (TPS) | ~8000/sec | ~9000/sec | ~10000/sec | Undertow 吞吐量最高,处理并发能力最强。 |
| 响应时间 (99%) | 1084 ms | 1067 ms | 1098 ms | 三者差异不明显,Jetty 略快,但都在可接受范围内。 |
| CPU 使用率 | > 70% | > 60% | ~50% | Undertow 的 CPU 负载最低,计算效率更高。 |
| 内存占用 | 高 (> 1.5G) | 中 | 低 | Undertow 内存占用最平稳且最低。 |
| 线程数占用 | 多 | 中 | 少 | Undertow 使用更少的线程完成了更多的请求。 |
数据解读:在吞吐量和资源消耗(CPU、内存、线程)这几个关键指标上,Undertow 均优于 Tomcat 和 Jetty。特别是在高并发场景下,Undertow 能用更少的资源处理更多的请求,这直接转化为服务器成本的节省。
17.1.3. RVP 的选择:为何默认排除 Tomcat 启用 Undertow?
基于上述压测数据,RVP 框架做出了明确的技术选型:弃用默认的 Tomcat,全面拥抱 Undertow。
Undertow 的核心特性完美契合了 RVP 作为企业级后台管理框架的需求:
- 支持 HTTP/2:开箱即用,提升传输效率。
- 非阻塞架构:基于 XNIO,在高并发 I/O 密集型任务中表现出色。
- 资源利用率高:在微服务或容器化部署场景下,低内存占用意味着可以用同样的硬件运行更多的实例。
17.2. RVP 中的 Undertow 配置
确定了选型,我们来看看 RVP 是如何在工程中落地 Undertow 的。这涉及到依赖替换、参数调优以及代码适配三个层面。
17.2.1. pom.xml:排除与引入
要替换默认容器,首先需要在 Maven 依赖中操作。
文件路径:ruoyi-common/ruoyi-common-web/pom.xml
1 | <dependencies> |
通过 <exclusions> 标签排除 Tomcat,并引入 spring-boot-starter-undertow,Spring Boot 的自动配置机制就会自动识别并启动 Undertow 服务器。
17.2.2. application.yml:核心参数调优
引入依赖只是第一步,Undertow 的性能发挥依赖于合理的参数配置。
文件路径:ruoyi-admin/src/main/resources/application.yml
我们来看 server.undertow 下的关键配置项:
1 | # 开发环境配置 |
配置详解:
buffer-size:每个缓冲区的大小。Undertow 会在内存中分配一块区域用于 I/O 操作。配置越小,空间利用率越高;配置过小,会导致频繁的读写操作。512字节是一个在 RVP 场景下的经验值。direct-buffers:设置为true启用堆外内存(Direct Memory)。这可以减少 JVM 堆内存与本地内存之间的数据拷贝,是 NIO 提升性能的关键。threads.io:IO 线程主要负责非阻塞的网络连接和读写。通常设置为 CPU 核心数(如 8 核设为 8)。threads.worker:Worker 线程负责执行具体的业务逻辑(Servlet 请求)。由于业务逻辑通常包含数据库查询等阻塞操作,这个值需要设置得比较大,取决于系统的负载预期。
17.2.3. UndertowConfig:虚拟线程适配与安全增强
在 RVP 5.x 中,除了基础的 yml 配置,RVP还通过 Java 代码对 Undertow 进行了深度定制。
文件路径:ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java
第一步:基础骨架与 WebSocket 支持
首先,我们需要让 Undertow 支持 WebSocket,并为其分配专用的直接内存缓冲区。
1 |
|
第二步:核心适配——虚拟线程池
这是 RVP 高并发性能的关键。当我们在 application.yml 中开启了虚拟线程开关后,这里会将 Undertow 的默认 Worker 线程池替换为 虚拟线程执行器。
1 | // ... (接上文) |
分析:这段代码让 Undertow 摆脱了物理线程数量的限制。在高并发场景下,它不再依赖有限的 worker-threads(默认 256),而是可以创建无限多的虚拟线程来处理请求,实现吞吐量的质变。
第三步:安全加固——禁用危险方法
最后,为了防止爬虫骚扰和潜在的安全风险,我们拦截并禁用了几个不常用的 HTTP 方法。
1 | // ... (接上文) |










