1. BIO(阻塞式I/O)
实现方式: org.apache.coyote.http11.Http11Protocol
<!-- server.xml配置 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<!-- 默认使用BIO(Tomcat 7及之前版本) -->
工作原理:
缺点:
- 连接数受线程数限制
- 大量空闲连接占用线程资源
- 上下文切换开销大
2. NIO(非阻塞I/O)
实现方式: org.apache.coyote.http11.Http11NioProtocol
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="200"
connectionTimeout="20000">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
核心组件:
- Selector(选择器):单线程管理多个连接
- Buffer(缓冲区):数据读写通过缓冲区进行
- Channel(通道):全双工通信通道
工作流程:
// NIO模式伪代码
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // 阻塞直到有事件
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) {
// 处理新连接
} else if (key.isReadable()) {
// 处理读事件(非阻塞)
channel.read(buffer);
} else if (key.isWritable()) {
// 处理写事件
}
}
}
Tomcat NIO架构:
┌─────────────────────────────────┐
│ NioEndpoint │
├─────────────────────────────────┤
│ Acceptor ──接收连接──→ Poller │
│ │ (轮询事件) │
│ ↓ ↓ │
│ Socket → SocketWrapper → Processor │
└─────────────────────────────────┘
优势:
- 一个线程处理多个连接
- 减少线程创建和上下文切换
- 适合长连接、高并发场景
3. AIO(异步I/O)
实现方式: org.apache.coyote.http11.Http11Nio2Protocol
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
maxThreads="200"
acceptorThreadCount="2"
connectionTimeout="20000"/>
特点:
- 真正的异步:I/O操作完成后回调,无需轮询
- Proactor模式:事件分离器等待异步操作完成通知
- 内核级支持:依赖操作系统AIO支持
AIO vs NIO:
BIO: 请求 → 线程阻塞等待 → 处理 → 响应
NIO: 请求 → 注册到Selector → 就绪时处理 → 响应
AIO: 请求 → 发起异步操作 → 完成后回调处理 → 响应
Tomcat中AIO现状:
- Tomcat 8开始支持
- 但Linux平台AIO实现不成熟,性能优势不明显
- Windows平台有较好支持
4. ARP/APR(Apache Portable Runtime)
实现方式: org.apache.coyote.http11.Http11AprProtocol
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="200"
SSLEnabled="true"
connectionTimeout="20000">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
核心特性:
- 本地库调用:通过JNI调用本地操作系统API
- 零拷贝技术:减少内存拷贝次数
- 事件驱动:使用epoll(Linux)/kqueue(BSD)/IOCP(Windows)
APR架构:
┌─────────────────────────────────────────┐
│ Tomcat JVM │
├─────────────────────────────────────────┤
│ APR Connector → JNI接口 → libtcnative │
│ ↓ ↓ │
│ Java层面 本地库(C/C++) │
│ ↓ │
│ 操作系统网络栈 │
└─────────────────────────────────────────┘
优势:
- 高性能:接近原生C/C++性能
- 更好的SSL性能
- 支持sendfile等高级特性
- 内存使用更高效
5. 性能对比与选择策略
| 特性 |
BIO |
NIO |
AIO |
APR |
|---|
| 并发模型 |
线程/连接 |
事件驱动 |
回调驱动 |
事件驱动 |
| 阻塞方式 |
同步阻塞 |
同步非阻塞 |
异步非阻塞 |
同步非阻塞 |
| 适用场景 |
低并发 |
高并发长连接 |
大文件传输 |
高性能需求 |
| 线程使用 |
高 |
中 |
低 |
低 |
| CPU使用 |
高 |
中 |
低 |
低 |
| 复杂度 |
低 |
中 |
高 |
高 |
| 平台依赖 |
无 |
无 |
高(Linux支持差) |
需要本地库 |
6. 配置示例与优化建议
NIO优化配置:
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="1000"
minSpareThreads="100"
acceptCount="1000"
maxConnections="10000"
connectionTimeout="20000"
enableLookups="false"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/json"
redirectPort="8443">
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>
APR启用步骤:
安装APR库:
# Ubuntu
sudo apt-get install libapr1-dev libssl-dev
CentOS/RHEL
sudo yum install apr-devel openssl-devel
2. 编译Tomcat Native:
```bash
cd $CATALINA_HOME/bin
tar xzf tomcat-native.tar.gz
cd tomcat-native-*/native
./configure --with-apr=/usr/bin/apr-1-config \
--with-java-home=$JAVA_HOME \
--with-ssl=yes \
--prefix=$CATALINA_HOME
make && make install
配置CATALINA_OPTS:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CATALINA_HOME/lib
7. 选择建议
传统应用:NIO(平衡性最好)
高并发长连接:NIO + WebSocket
静态文件服务器:APR(sendfile支持)
HTTPS密集型:APR(SSL性能好)
Windows服务器:可尝试AIO
兼容性优先:BIO(遗留系统)
8. 监控与调优
查看当前连接器:
# 访问Tomcat Manager或查看日志
# 日志中会显示:Starting ProtocolHandler ["http-nio-8080"]
关键监控指标:
currentThreadCount:当前线程数
currentThreadsBusy:繁忙线程数
connectionCount:连接数
requestCount:请求计数
JVM参数优化:
# NIO/AIO需要更多直接内存
-XX:MaxDirectMemorySize=256M
# APR需要设置本地库路径
-Djava.library.path=/usr/local/apr/lib
总结
Tomcat的连接器演进反映了Java Web服务器技术的发展:
- BIO:简单但低效,适合教学和小应用
- NIO:当前主流,平衡性能和复杂度
- AIO:理论最优,但平台支持限制
- APR:性能极致,但部署复杂
现代Tomcat最佳实践:
- Tomcat 8+ 默认使用NIO
- 生产环境推荐:NIO + 适当调优
- 特殊场景(SSL/静态文件)考虑APR
- 始终根据实际压力测试结果选择