从 Tomcat 与 Jetty 的对比,聊聊影响一个服务并发能力的关键因素

作者:G探险者日期:2025/10/16

大家好,我是G探险者!

在 Java 服务体系中,TomcatJetty 是最常见的 Web 容器。很多人认为,只要加大连接数或线程数,就能提升并发能力。
但事实远比想象复杂:连接数只是冰山一角,背后还有线程模型、I/O 模型、内核资源限制等多重因素。

本文从 Tomcat 与 Jetty 的对比 入手,系统讲清楚——到底是什么在决定你的服务并发上限。


🧩 一、Tomcat 与 Jetty 的架构差异

1️⃣ Tomcat 的工作模型

Tomcat 默认采用 多线程 + 阻塞 I/O (BIO/NIO) 模型。
它通过 maxConnections 限制 TCP 连接数,通过 maxThreads 限制同时处理的请求线程。

简化模型如下:

1[客户端连接] → [TCP连接池 (maxConnections)] 
23[请求队列 (acceptCount)] 
45[线程池 (maxThreads)] → [业务处理]
6
7
  • 一个请求在被线程接管后,线程会一直阻塞直到请求完成。
  • 若请求阻塞(如访问数据库或远程服务),线程被占用,会直接影响整体并发。

2️⃣ Jetty 的工作模型

Jetty 默认使用 非阻塞 NIO 模型,基于 Reactor 模式。
它的核心理念是:

用少量 Selector 线程负责所有连接的读写事件,用工作线程处理真正的业务逻辑。

模型如下:

1[客户端连接] → [Selector线程 (少量)]
23[事件分发] → [工作线程池 (maxThreads)] → [业务处理]
4
5

优势:

  • 一个线程可同时管理上千连接(非阻塞 I/O);
  • 支持更高的空闲连接与 KeepAlive 连接数;
  • 在高并发长连接场景(如 WebSocket、HTTP/2)中明显优于 Tomcat。

⚙️ 二、Tomcat 与 Jetty 的默认并发参数对比

项目Tomcat(Spring Boot 默认)Jetty(Spring Boot 可选)说明
默认线程数200 (server.tomcat.max-threads)200 (QueuedThreadPool.maxThreads)可同时处理请求的线程数
默认最大连接数10000 (server.tomcat.max-connections)无固定值(由 Selector 与 OS 限制)同时打开的 TCP 连接数上限
默认等待队列100 (server.tomcat.accept-count)内部队列(动态)连接满后等待请求数
I/O 模型阻塞式 NIO事件驱动式 NIO决定每个线程能管理多少连接
KeepAlive 管理每连接占线程资源非阻塞复用线程Jetty 更高效
配置灵活性通过 server.tomcat.*通过 server.jetty.* 或 Java APIJetty 灵活但复杂
典型并发能力5K~10K(视CPU与内存)10K~30K(视操作系统限制)Jetty 在高连接数场景下优势明显

🔍 三、影响服务并发能力的核心因素

很多人只调 maxThreadsmaxConnections,其实那只是表象。
一个服务的真正并发能力受以下五个层面的影响:


1️⃣ 应用层:线程模型与I/O模型

模型类型代表容器特点并发能力
BIO(阻塞IO)Tomcat早期版本每连接占线程
NIO(非阻塞IO)Tomcat 8+/Jetty一个线程可处理多个连接中高
AIO(异步IO)Jetty/Undertow/Netty完全事件驱动

🧠 结论
选择非阻塞 I/O(如 Jetty、Netty)通常能显著提升并发上限。


2️⃣ 容器层:线程池与连接池配置

以 Tomcat 为例:

1server.tomcat.max-connections=20000
2server.tomcat.max-threads=500
3server.tomcat.accept-count=1000
4
5
  • maxConnections:并发TCP连接上限
  • maxThreads:同时处理请求上限
  • acceptCount:连接满后的排队长度

如果线程数配置过低,CPU空闲但请求积压;
配置过高,又会导致频繁上下文切换,反而变慢。

🧠 经验值

  • CPU密集型应用:maxThreads ≈ 核数 × 2
  • I/O密集型应用:maxThreads ≈ 核数 × 5~10

3️⃣ 系统层:操作系统文件描述符与TCP栈

操作系统对连接的限制非常关键:

限制项Linux参数说明
最大文件描述符数ulimit -n每个连接占一个fd
TCP backlog 队列/proc/sys/net/core/somaxconn等待接入的连接队列
TIME_WAIT 超时/proc/sys/net/ipv4/tcp_fin_timeout连接关闭延迟释放
端口复用/proc/sys/net/ipv4/tcp_tw_reuse减少端口耗尽

⚠️ 若 ulimit -n 太小(如 1024),即使 Tomcat 配了 20000 连接也无法生效。


4️⃣ 数据库层:连接池与事务等待

应用层的高并发最终要落到数据库连接上。
若连接池上限(如 HikariCP 的 maximumPoolSize)太小,会出现:

“Tomcat 能接 2000 个请求,但只有 50 个能访问数据库,其他都在排队。”

🧠 调优思路:

  • DB连接数 ≈ 应用活跃线程数 × 访问数据库比例
  • 用缓存/异步队列减少数据库访问占比

5️⃣ 网络层:负载均衡与KeepAlive策略

  • KeepAlive 过短 → 频繁重建连接,耗时;
  • KeepAlive 过长 → 连接资源被空闲占用;
  • 负载均衡(如 Nginx) 的超时与连接复用策略,也会直接影响并发稳定性。

🧠 建议:

  • 对静态请求使用 KeepAlive;
  • 对动态或长轮询请求启用超时检测与连接回收;
  • 配合 Nginx 使用 keepalive_timeout 30smax_fails 等策略。

📈 四、Tomcat 与 Jetty 并发性能对比总结

维度TomcatJetty
适用场景标准Web应用(同步请求为主)高并发、长连接、WebSocket
默认配置守旧(maxThreads=200)灵活、事件驱动
可维护性Spring Boot默认支持最佳可扩展性强(嵌入式更灵活)
性能瓶颈线程阻塞、队列等待网络带宽、Selector数量
调优重点maxThreads / maxConnections线程池与连接限制Bean
理论并发上限1万左右2万~3万以上(视系统资源)

🧠 简单说:

  • Tomcat 胜在稳定与生态;
  • Jetty 胜在轻量与高并发。

🧭 五、结语:并发的核心不止“连接数”

很多人问:“Tomcat 支持 10000 连接,我能处理 10000 并发吗?”
答案是:不一定。

因为:

  • 并发连接数 ≠ 并发请求数;
  • 并发请求数 ≠ 并发业务处理数;
  • 真正能撑起高并发的,是架构、线程模型、系统配置与资源调度的整体平衡

🧠 最佳实践:

  1. 调优容器参数(连接数、线程数、队列长度);
  2. 优化应用逻辑(异步化、减少阻塞);
  3. 提升系统层资源限制(ulimit -n、TCP参数);
  4. 引入缓存与异步解耦(Redis、MQ);
  5. 在高并发长连接场景下,考虑 Jetty 或 Netty 替代 Tomcat。

✅ 总结一句话

影响服务并发能力的核心,不只是连接数。
它取决于:

  • 容器的 I/O 模型(阻塞 / 非阻塞)
  • 线程池与连接池配置
  • 操作系统资源限制
  • 后端依赖(数据库 / MQ)性能

而 Tomcat 与 Jetty 的差异,恰好体现了“并发设计哲学”的两种思路:

  • Tomcat:稳定可靠的线程池模型
  • Jetty:事件驱动的高连接复用模型


从 Tomcat 与 Jetty 的对比,聊聊影响一个服务并发能力的关键因素》 是转载文章,点击查看原文


相关推荐


面试真实经历某商银行大厂Java问题和答案总结(三)
360_go_php2025/10/15

​ 1. 深拷贝和浅拷贝 ​编辑 问:什么是深拷贝和浅拷贝?它们之间有什么区别? 浅拷贝(Shallow Copy): 浅拷贝指的是复制对象的引用,而不是复制对象本身。也就是说,对于对象中的引用类型字段,浅拷贝只是复制了这些字段的引用,而没有复制字段引用的对象本身。 如果原始对象和拷贝对象中有相同的引用类型字段,修改其中一个字段会影响到另一个对象。​编辑 深拷贝(Deep Copy): 深拷贝指的是复制对象本身,并且递归地复制对象中的所有引用类型字段,确保两个对象中的引用类型字段互不影响。


Swift 基础语法全景(一):从变量到类型安全
unravel20252025/10/14

常量与变量:let vs var 声明语法 // 常量:一次赋值,终身不变 let maximumLoginAttempts = 10 // 最大尝试次数,业务上不允许修改 // 变量:可反复写入 var currentAttempt = 0 // 当前尝试次数,失败+1 延迟赋值 只要「第一次读取前」完成初始化即可,不必一行写完。 var randomGenerator = SystemRandomNumberGenerator() let


Linux挂载NTFS分区指南
依赖倒不置2025/10/12

在使用Windows和Linux双系统的电脑上,通常我们可能也需要在Linux上访问NTFS分区。虽然Linux用户一般来说不一定会有分区的习惯,但是在双系统情况下,两个系统复用NTFS分区也是很常见的。 今天,就来讨论双系统复用分区的场景下,如何正确地在Linux挂载NTFS分区。 1,Linux的NTFS驱动 事实上,老版本的Linux内核并不原生支持读取NTFS分区,尤其是NTFS是Windows系统专有的文件系统,而不是开放的。因此很长一段时间,都是使用ntfs-3g这个开源驱动实现在L


老题新解|十进制转二进制
程序员莫小特2025/10/10

《信息学奥赛一本通》第160题:十进制转二进制 题目描述 给定一个十进制整数 n n n,请将其转换为对应的二进制表示,并输出。 输入格式 输入包含一行,一个整数 n


单机已达上限?PerfTest 分布式压测登场,轻松模拟百万用户洪峰
Go有引力2025/10/9

前言 在前一篇文章中,我们详细介绍了 perftest 的单机压测能力,展示了它如何通过极简的命令行实现对 HTTP/1.1、HTTP/2、HTTP/3 与 WebSocket 的高性能测试。然而,当业务系统庞大、服务部署分布式、网络链路复杂时,单机的压测能力显然无法满足真实生产环境的模拟需求。 幸运的是,perftest 不止于单机。它同样支持 分布式集群压测,通过 Collector + Agent 的架构,让你轻松在多台机器上同时发起测试,实现百万乃至千万级并发的性能评估。 为什么选择分


Webpack实战笔记:从自动构建到本地服务器搭建的完整流程
XiangCoder2025/10/7

作为前端开发者,Webpack 是绕不开的构建工具。最近系统学习了 Webpack 的自动构建和服务器搭建,整理了一套从基础到实战的操作笔记,包含具体案例和踩坑经验,适合新手跟着实操。 前言:为什么需要 Webpack 构建工具? 刚开始写前端项目时,我们习惯在 index.html 里手动引入各种 js、css 文件。但随着项目变大,会遇到两个核心问题: 资源越来越多,手动管理引入路径容易出错(尤其是加哈希值优化缓存时); 开发时需要频繁刷新页面看效果,效率太低。 Web


Android系统模块编译调试与Ninja使用指南
龙之叶2025/10/6

模块编译调试方法 (此处举例framework、installd、SystemUI等模块的编译调试,其他类似) 1. Framework模块编译 Android系统代码的framework目录内,一共有3个模块单独编译:framework、services、framework-res.apk。 注意:偶尔会有改了代码但没检测到,编译结束后产物并未更新的情况,所以可以考虑先剪切掉原先的产物或者检查产物更新时间确保已经重新编译。 步骤: 完成根目录下 source build/envsetup.sh


精选 4 款开源免费、美观实用的 MAUI UI 组件库,助力轻松构建美观且功能丰富的应用程序!
追逐时光者2025/10/5

前言 一套优秀的 UI 组件库不仅能大幅提升开发效率,还能显著增强应用的视觉体验与交互质感。今天大姚给大家分享 4 款开源免费、美观实用的 MAUI UI 组件库,助你轻松打造专业级的跨平台应用程序。 .NET MAUI介绍 .NET 多平台应用 UI (.NET MAUI) 是一个跨平台框架,用于使用 C# 和 XAML 创建本机移动和桌面应用。使用 .NET MAUI,可从单个共享代码库开发可在 Android、iOS、macOS 和 Windows 上运行的应用。 .NET开源免费的跨平


医院病人信息管理系统 Web 版开发实战(一)
FPGA+护理+人工智能2025/10/3

医院病人信息管理系统Web版开发实战 文章目录 医院病人信息管理系统Web版开发实战一、概述二、项目结构搭建2.1 Flask 项目结构原理2.2 创建项目文件夹2.3 初始化 Flask 应用 三、路由设计3.1 Flask 路由机制原理3.2 定义核心路由3.3 数据存储函数 四、模板开发4.1 Jinja2 模板引擎原理4.2 基础模板设计4.3 首页模板(index.html)4.4 添加病人模板(add.html)4.5 详情和编辑模板 未完待续


Java-Spring入门指南(十一)代理模式与Spring AOP实战
珹洺2025/10/2

Java-Spring入门指南(十一)代理模式与Spring AOP实战 前言一、代理模式1.1 静态代理步骤1:定义租房接口(抽象行为)步骤2:实现房东类(真实对象)步骤3:编写中介类(代理对象)步骤4:测试静态代理静态代理的优缺点 1.2 动态代理 二、AOP是什么?2.1 AOP是什么?2.2 AOP有什么用?2.3 AOP的使用场景是什么?2.4 AOP的核心特点是什么? 三、AOP在Spring中的应用3.1 准备依赖3.2 配置Spring的AOP命名空间3.3 定义

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0