介绍下 Tomcat 10(10.1.x,NIO) 的连接管理模型 。内容从 整体架构 → 线程/连接角色 → 生命周期 → 状态转换 → 与 Spring Boot 内嵌模式的关系 → 常见瓶颈,形成一个"可用于排障和调优"的模型
一、整体架构总览(Tomcat 10 NIO)
Tomcat 10 默认使用 HTTP/1.1 NIO Connector (Http11NioProtocol),其连接管理是事件驱动 + 线程池执行模型:
┌───────────┐
│ Acceptor │ 接受 TCP 连接
└─────┬─────┘
│
▼
┌───────────────────┐
│ Endpoint │
│ (NioEndpoint) │
└─────┬─────────────┘
│
┌─────────▼─────────┐
│ Poller │ 连接管理核心(Selector)
│ (connection pool)│
└─────────┬─────────┘
│ 事件触发
▼
┌─────────────────────┐
│ Executor / │
│ Worker Threads │ 执行业务
└─────────────────────┘
核心思想 :
连接(Socket)与线程(Request 处理)分离连接由 Poller 管,线程只在"真正处理请求"时使用。
二、核心组件与职责
1️⃣ Connector / Endpoint
-
负责网络层
-
参数:
maxConnections,acceptCount,connectionTimeout -
在 Tomcat 10 中默认实现是:
org.apache.tomcat.util.net.NioEndpoint
Endpoint 管三件事:
- Acceptor(接连接)
- Poller(管连接)
- SocketWrapper / Buffer 池
2️⃣ Acceptor(接入层)
职责
- 调用
ServerSocketChannel.accept() - 创建
SocketChannel - 注册到 Poller
关键参数
acceptCount:backlog 队列- 受 OS
somaxconn影响
特点
- 不处理请求
- 只负责把连接交给 Poller
- 通常 1 个线程
3️⃣ Poller(连接管理核心)
职责(非常重要)
-
维护 Selector
-
管理所有活跃 Socket
-
监听事件:
- READ
- WRITE
- TIMEOUT
-
管理 keep-alive
-
管理 Socket 状态机
Poller = Tomcat 的"连接池"
- 所有 Socket(包括 idle)都在这里
- 受
maxConnections限制
CLOSE_WAIT / ESTABLISHED / IDLE 都属于 Poller 管理范围
4️⃣ Executor / Worker 线程池
职责
- 处理 HTTP 请求
- 调用 Filter / Servlet / Spring MVC
- 不管理连接生命周期
关键参数
maxThreadsminSpareThreads
三、连接生命周期(一次完整 HTTP/1.1)
Step 1:建立 TCP 连接
Client → SYN
Server → SYN+ACK
Client → ACK
→ Acceptor 接收
→ 注册到 Poller
→ 状态:ESTABLISHED (IDLE)
Step 2:接收请求数据
- Poller 监听到 READ 事件
- 创建
Http11Processor - 投递给 Executor
Step 3:业务处理
-
Worker 线程处理:
- Filter
- Servlet
- Spring Controller
-
构建 Response
Step 4:响应写回
- Poller 负责 WRITE
- Response 写回 socket
Step 5:连接去向
✔ keep-alive
IDLE → Poller
✔ 非 keep-alive
close() → TIME_WAIT
四、连接状态机(简化)
NEW
↓
ESTABLISHED
↓
READING
↓
PROCESSING (worker)
↓
WRITING
↓
IDLE (keep-alive)
↓
CLOSED / TIME_WAIT
⚠️ 如果:
- 客户端先 close
- Tomcat 未 close
→ CLOSE_WAIT
五、Tomcat 10 的关键限制点
1️⃣ maxConnections(连接池上限)
-
默认:8192
-
包含:
- idle keep-alive
- 正在处理
- CLOSE_WAIT(未 close)
超过后:
- 新连接进入 acceptCount
- 再超 → 拒绝连接
2️⃣ maxThreads(业务并发上限)
- 你配置:800
- 只限制"正在处理的请求"
- 不限制连接数
3️⃣ acceptCount(缓冲区)
- 你配置:1000
- TCP 层 backlog
六、Spring Boot 内嵌 Tomcat 的映射关系
yaml
server:
tomcat:
max-connections: 8192
accept-count: 1000
threads:
max: 800
| Spring Boot | Tomcat |
|---|---|
| max-connections | Endpoint.maxConnections |
| accept-count | Acceptor backlog |
| threads.max | Executor.maxThreads |
七、Tomcat 10 的几个"反直觉点"(很重要)
❗ 1. 连接多 ≠ 线程多
- 10k 连接
- 800 线程
- 完全正常
❗ 2. CLOSE_WAIT 会吃掉连接池
- 不会自动释放
- 是服务端 bug 信号
❗ 3. Poller 不等于线程池
- Poller 是 I/O 事件循环
- Executor 是业务执行
八、常见问题与调优方向
你遇到的:
CLOSE_WAIT ≈ 3700 → 服务不可用
在 Tomcat 10 模型下意味着:
- Poller 的连接池被"半死连接"占满
- Acceptor 无法接新连接
- 表现为端口存在但无响应
九、一句话总结(工程视角)
Tomcat 10 采用"事件驱动连接管理 + 线程池业务处理"的模型,Poller 统一管理 Socket 生命周期,Executor 只在请求处理阶段介入;任何 CLOSE_WAIT 的累积都会直接耗尽连接池,导致服务雪崩。