导读:本期聚焦于勇士创作的《Spring Boot 嵌入式 Servlet 容器如何选型与调优?Tomcat、Jetty、Undertow 对比解析》,敬请观看详情。Tomcat、Jetty、Undertow 是 Java 生态中常用的嵌入式 Servlet 容器,Spring Boot 默认选择 Tomcat,但很多项目在切换到 Jetty 或 Undertow 后获得了不同的性能表现。本文将围绕三者在线程模型、内存占用、并发处理、协议支持等方面的差异展开对比,并结合实际场景给出选型建议。调优部分会覆盖线程池参数、连接队列、超时时间、IO 模型、缓冲区和异步处理等关键配置,同时提供 properties 与 Java 配置示例。文章还会指出常见误区,例如盲目调大线程数可能适得其反,以及容器切换时需要注意的兼容性问题。无论你是微服务架构下的中小型应用,还是追求高并发低延迟的接口服务,都能从中找到适合自己的容器与调优方案。

在 Spring Boot 应用中,嵌入式 Servlet 容器承担着接收 HTTP 请求、管理连接、驱动 Servlet 生命周期的职责。Tomcat 是默认选择,但 Jetty 和 Undertow 在特定场景下往往能带来更低的资源占用或更高的并发吞吐。理解三者的线程模型与配置差异,比单纯更换依赖更重要,因为调优的本质是让容器行为和业务负载相匹配。

Spring Boot 嵌入式 Servlet 容器如何选型与调优?Tomcat、Jetty、Undertow 对比解析

运行模型差异:线程策略决定吞吐上限

Tomcat 从 8.x 开始默认使用 NIO 连接器,一个连接并不会永久独占工作线程,但在执行 Servlet 的读写操作时,工作线程仍然会阻塞到业务处理完成。这种模型对传统的请求-响应式应用很友好,开发人员也习惯在线程局部变量中保存上下文。然而当并发连接数很高、请求处理时间较长或存在大量长连接时,线程池的调度开销会逐渐成为瓶颈。

Jetty 同样基于 NIO,不过它的连接处理和线程池设计更加轻量。Jetty 内部大量使用异步回调,对空闲连接的清理和超时控制更精细,适合需要维持大量 WebSocket 长连接的场景。Undertow 则走得更彻底,底层使用 XNIO,将 IO 线程与工作线程明确分离。IO 线程只负责网络事件读写,真正的业务逻辑由独立的工作线程池执行,这种设计能够用较少的线程支撑较高的并发,尤其适合低延迟、非阻塞风格的服务。

三种容器的差异并不是单纯的优劣对比,而是取舍不同。Tomcat 胜在稳定和生态兼容性,Jetty 偏向轻量和嵌入灵活,Undertow 追求高并发下的低资源消耗。选型前要明确应用是计算密集、IO 密集还是长连接密集,因为不同类型的负载对线程模型的敏感度完全不同。

选型维度:并发、内存、协议与生态兼容性

如果项目追求的是稳定性和最广泛的兼容性,Tomcat 仍是优先级最高的选择。大部分第三方监控、部署工具和运维平台都对 Tomcat 有成熟支持,遇到问题时解决方案也更容易找到。若应用需要嵌入到其他系统中,或者内存预算非常有限,Jetty 的轻量体积和模块化设计会带来明显优势。

对于高并发、大量短连接或需要与 Netty 等非阻塞框架协同工作的服务,Undertow 的表现通常更突出。它在基准测试中往往能以较少的内存占用获得更高的每秒处理能力,尤其是在接口逻辑较轻、IO 等待比例较高的场景下。协议支持方面,三者都已支持 HTTP/2 和 WebSocket,但开启方式和配置细节略有不同,建议结合自己的基础设施统一规划。

切换容器时,可以通过 Maven 配置排除默认依赖。以下是一个使用 Undertow 替换 Tomcat 的示例:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

这段配置会从 Web 启动器中移除 Tomcat,再加入 Undertow 的启动器。如果选择 Jetty,只需将第二个依赖替换为 spring-boot-starter-jetty。需要注意的是,某些基于 Tomcat 特定 API 的代码或过滤器在切换后可能会失效,因此切换前应做完整的回归测试。

通用调优参数:线程池、连接队列与超时

嵌入式容器的调优大多集中在线程池和连接管理上。以 Tomcat 为例,server.tomcat.threads.max 控制最大工作线程数,min-spare 控制最小空闲线程数。线程数并非越大越好:线程过多会导致频繁的上下文切换,且每个线程都会占用一定的栈内存。一般建议先通过压测找到当前 CPU 核数下的最佳并发区间,再逐步调整。

连接队列和超时参数同样关键。accept-count 表示当所有工作线程都在忙碌时,操作系统还能接受的等待连接数;超过这个数量的连接会被拒绝。这个值过小会导致突发流量下大量请求直接失败,过大会增加请求排队延迟。合理的做法是结合客户端重试机制,将等待队列控制在一个可接受的范围内,让系统快速失败而不是长时间无响应。

下面的配置展示了一组适合中等规模 Web 服务的 Tomcat 参数:

server.tomcat.threads.max=200
server.tomcat.threads.min-spare=20
server.tomcat.accept-count=100
server.tomcat.max-connections=10000
server.tomcat.connection-timeout=5000
server.tomcat.keep-alive-timeout=10000

Java 配置类也可以实现同样的效果,便于在代码中根据环境动态调整。例如通过实现 WebServerFactoryCustomizer 接口来统一管理容器参数:

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TomcatTuningConfig implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    @Override
    public void customize(ConfigurableServletWebServerFactory factory) {
        if (factory instanceof TomcatServletWebServerFactory) {
            TomcatServletWebServerFactory tomcat = (TomcatServletWebServerFactory) factory;
            tomcat.addConnectorCustomizers(connector -> {
                Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
                protocol.setMaxThreads(200);
                protocol.setMinSpareThreads(20);
                protocol.setAcceptCount(100);
                protocol.setMaxConnections(10000);
                protocol.setConnectionTimeout(5000);
                protocol.setKeepAliveTimeout(10000);
            });
        }
    }
}

这段代码针对 Tomcat 的 NIO 协议处理器进行定制。如果切换到 Jetty 或 Undertow,配置方式不同,但调整的核心思想是一致的:工作线程数量适中、等待队列有边界、超时时间与业务响应时间匹配。

容器特定调优与常见避坑点

不同容器还提供了一些专属参数。Undertow 通过 server.undertow.threads.io 设置 IO 线程数,通常建议与 CPU 核数相当;server.undertow.threads.worker 设置工作线程数,需要根据业务阻塞程度调整。Jetty 的线程池可以通过 server.jetty.threads.max 和 server.jetty.threads.min 控制,此外还可以设置 server.jetty.max-http-form-post-size 来限制表单提交大小,避免内存被意外撑爆。

Tomcat 方面,除了线程参数,还有 max-keep-alive-requests 控制 keep-alive 连接上最多处理的请求数,超过后主动关闭连接,有助于防止连接长时间占用资源。如果不需要 AJP 协议,务必确保 AJP 连接器未被启用,历史上 AJP 相关的安全漏洞不少,禁用它可以减少攻击面。

调优过程中有一些常见误区。比如以为把所有超时时间调大就能减少连接断开,实际上是让半死不活的连接占着资源;还有人在切换到 Undertow 后仍然沿用 Tomcat 的线程数配置,导致工作线程过多而 IO 线程不足。最稳妥的方式是每次只调整一个关键参数,用压测数据验证收益,再决定是否继续叠加变化。

另一个容易忽略的点是异步请求的支持。如果业务中使用了 DeferredResult 或 Servlet 3.1 的异步特性,要确保容器的异步超时和线程池配置与异步执行器协调一致,否则可能出现请求线程被快速耗尽或异步任务被提前中断的情况。

嵌入式Servlet容器Tomcat调优Jetty调优修改时间:2026-10-06 20:00:17

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1006/66565.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。