Tomcat NIO 工作原理详解:从 Acceptor、Poller 到容器处理链

平时写 Spring Boot 接口时,我们通常只关心 Controller 能不能收到请求,很少去想 Tomcat 在这之前做了什么。没有把请求是如何流转的讲清楚。要理解 Tomcat NIO,抓住 Acceptor、Poller 和 Worker 三类线程就够了。

一、一次请求是怎样被 Tomcat 处理的

先来看一条简化后的处理链路:

复制代码
客户端连接
   ↓
Acceptor 接收连接
   ↓
Poller 监听读写事件
   ↓
Worker 解析并处理请求
   ↓
Engine → Host → Context → Wrapper
   ↓
Servlet / Controller

这三类线程并不是重复做同一件事,而是把"接收连接""等待数据"和"执行业务"拆开处理。

1. Acceptor:负责接收连接

Acceptor 可以理解为 Tomcat 的接待人员。它会阻塞在服务端端口上,等待客户端建立 TCP 连接。连接建立后,Acceptor 对 Socket 做一些基础配置,然后把它交给 Poller 管理。

Acceptor 只负责接收和移交连接,并不会一直跟着某个客户端,更不会亲自执行 Controller 中的业务代码。正因为它的工作比较轻,一般不需要为每个连接创建一个 Acceptor 线程。

2. Poller:负责监听事件

连接交给 Poller 后,会注册到 Java NIO 的 Selector 上。Poller 可以同时观察很多连接,判断哪些连接已经准备好读取数据,或者具备写回响应的条件。

如果客户端只是保持 Keep-Alive,却暂时没有发送新请求,Poller 只需要继续监听它,不必让一个业务线程阻塞在那里等待。这正是 NIO 能管理大量连接的关键。

当 Selector 发现某个连接已经有数据可读时,Poller 会为它创建处理任务,并提交给线程池。

3. Worker:负责真正处理请求

线程池中的工作线程通常被称为 Worker。它会读取并解析 HTTP 报文,生成 Request 和 Response 对象,再通过 Tomcat 的适配与容器处理链,把请求交给对应的 Servlet。

如果项目使用 Spring MVC,请求最终还会进入 DispatcherServlet,之后才匹配到我们编写的 Controller。

因此,Tomcat NIO 并不是完全不使用线程,而是让线程用在真正需要计算和处理业务的阶段。连接处于空闲等待状态时,由少量 Poller 线程统一管理。

二、为什么 Tomcat 8.5 以后不再使用 BIO

传统 BIO 的思路比较直接:接收到一个连接后,通常由一个线程负责处理。当客户端迟迟不发送数据,或者使用 Keep-Alive 保持连接时,这个线程可能一直处于阻塞状态。

如果同时只有几十个连接,BIO 的问题并不明显。但连接数量上升到几千甚至更多时,大量线程会带来明显成本:

  • 每个线程都需要占用栈内存;

  • 线程数量过多会增加上下文切换;

  • 很多线程并没有执行业务,只是在等待网络数据;

  • 突发流量下容易迅速耗尽线程资源。

NIO 将"等待网络事件"和"处理业务请求"分开。一个 Poller 可以监听大量连接,只有连接真正就绪时才提交给 Worker。这样可以用相对有限的工作线程支撑更多并发连接。

需要注意的是,NIO 不一定让单个请求执行得更快。如果一条 SQL 本身需要两秒,换成 NIO 也不会让它自动变成两百毫秒。NIO 的主要价值,是减少连接等待期间的线程浪费,提高服务器管理并发连接的能力和整体吞吐量。

三、Tomcat 支持哪些 I/O 模型

不同版本的 Tomcat 支持情况并不完全相同,可以按下面的方式理解:

I/O 模型 特点 目前的情况
BIO 阻塞式 I/O,连接等待时容易占用线程 Tomcat 8.5 起已移除
NIO 基于 Selector 进行事件轮询 当前最常用,也是默认选择
NIO2 基于 Java 7 的异步通道 API 可以使用,但实际项目中不如 NIO 常见
APR/native 借助本地库实现网络和 TLS 能力 属于历史上常见的 Connector;新版本主要保留 Native 对 OpenSSL 的支持

常见的 NIO Connector 配置如下:

复制代码
<Connector
    port="8080"
    protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="200"
    maxConnections="8192"
    acceptCount="100" />

如果使用 NIO2,可以把协议类改为:

复制代码
org.apache.coyote.http11.Http11Nio2Protocol

日常项目没有明确需求时,使用默认 NIO 即可。不要仅仅因为 NIO2 名字里多了一个"2",就认为它一定比 NIO 快。最终效果仍然要结合操作系统、JDK、业务类型和压测结果判断。

四、Tomcat Engine 的作用

一个 Service 可以关联多个 Connector,但只关联一个 Engine。比如 Tomcat 同时提供 HTTP 和 AJP Connector,它们接收到的请求最终都可以交给同一个 Engine 处理。

Engine 的主要作用是:

  • 接收当前 Service 下各个 Connector 转交的请求;

  • 根据请求中的主机信息选择对应的 Host;

  • 找不到匹配主机时使用 defaultHost;

  • 通过自己的 Pipeline 和 Valve 执行访问日志、认证等公共处理;

  • 把响应沿原来的链路交还给 Connector。

Engine 不负责监听 8080 端口,也不直接管理 TCP 连接。端口监听属于 Connector 的职责,Engine 关注的是请求进入 Servlet 容器之后应该交给哪个应用处理。

五、Container 体系中的四种子容器

Tomcat 的 Container 接口有四种重要的子容器:Engine、Host、Context 和 Wrapper。它们是一层包含一层的关系。

容器 表示的含义 常见例子
Engine 整个 Catalina Servlet 引擎 一个 Service 对应一个 Engine
Host 一个虚拟主机 www.example.com
Context 一个 Web 应用 /shop
Wrapper 一个具体的 Servlet DispatcherServlet

假设用户访问:

复制代码
http://www.example.com:8080/shop/order/list

Tomcat 会先由 Connector 接收请求,然后按照下面的思路寻找处理目标:

  1. Engine 接收 Connector 转交的请求;

  2. 根据 www.example.com 找到对应的 Host;

  3. 根据 /shop 找到部署的 Context;

  4. 根据 Servlet 映射找到对应的 Wrapper;

  5. Wrapper 管理并调用具体 Servlet。

在 Spring Boot 项目中,这个 Servlet 通常就是 DispatcherServlet。至于 /order/list 对应哪个 Controller 方法,则由 Spring MVC 在进入 DispatcherServlet 后继续完成匹配。

这种分层并不是为了把结构设计得复杂,而是让每层只负责一种范围:Engine 管整个引擎,Host 管域名,Context 管应用,Wrapper 管 Servlet。

参考资料

相关推荐
nice_lcj5203 小时前
ThreadLocal 入门:它是怎么隔离数据的、为什么会导致内存泄漏
java·开发语言·后端·面试·并发编程·内存泄漏·threadlocal
秋天的怀念_David3 小时前
算法一千零一夜 · 第二十六夜 协议的母语
java·spring boot·算法
灿飞3 小时前
Kotlin与Java虚拟机八:控制流与 when:卫语句、上下文相关解析与穷尽性
java·kotlin
文丑颜不良啊4 小时前
LeetCode2021~2040题目解析
java·leetcode
bksczm4 小时前
InnoDB 行格式详解:DYNAMIC / COMPACT / COMPRESSED / REDUNDANT
java·开发语言·数据库
liangbo75 小时前
Spring系列03:Bean 的三种注册方式
java·spring
余槐i5 小时前
MySQL 8.0 联合索引走错:为什么加了索引查询反而从 200ms 变成 8s
java·spring boot·mysql·docker·性能优化
SL_staff5 小时前
制造业订单交付总在最后一刻爆雷?用结构化计划模板打通跨系统协同断点
java·开源·全栈
做科研的周师兄5 小时前
【R语言实战】MixSIAR 氢氧同位素水源解析全流程:从混合空间校验到贝叶斯 MCMC 收敛诊断(后附完整代码)
java·大数据·开发语言
有点小困9775 小时前
Spring Boot 异步任务 ClassLoader 踩坑实录:ClassNotFoundException 的诡异真相
java