Tomcat线程模型
目录
1 Linux I/O模型
2 Linux I/O模型分类
3 Tomcat支持的I/O模型
4 Tomcat I/O模型选型
5 Tomcat NIO实现
6 Tomcat异步IO实现
1 Linux I/O模型
- I/O:在计算机内存和外部设备之间拷贝数据的过程
- 程序通过cpu向外部设备发出读指令,数据从外部设置拷贝至内存需要一段时间,这段时间cpu是空闲的,此时程序会有两种选择:
- 让出cpu资源,让其干其他事
- 继续让cpu不停地查询数据是否拷贝完成
- 采用哪种策略就是I/O模型需要解决的事
- 一个进程的地址空间分为用户空间和内核空间
- 用户程序只能访问用户空间,内核进程可以访问整个进程空间
- 只有内核才可以直接访问各种硬件资源,比如磁盘和网卡
- 当cpu从网络读取数据时,分为两个阶段
- 数据准备阶段:将数据从网卡拷贝到内核空间
- 数据拷贝阶段:将数据从内核空间拷贝到用户空间
- 不同的I/O模型对以上两个步骤有不同的实现
2 Linux I/O模型分类
- 同步阻塞I/O
- 同步非阻塞I/O
- I/O多路复用
- 信号驱动式I/O
- 异步I/O
- 阻塞或非阻塞是指应用程序在发起I/O操作时,是立即返回还是等待
- 同步或异步是指应用程序在与内核通信时,数据从内核空间到应用空间的拷贝,是由内核主动发起还是由应用程序
java中支持的I/O模型有同步阻塞I/O,I/O多路复用,异步I/O等
3 Tomcat支持的I/O模型
tomcat中支持的I/O模型有:
IO模型 | 描述 |
BIO(BioEndpoint) | 同步阻塞式IO 该模式下每个请求都会占用一个线程,对性能开销大,不适合高并发场景 但是稳定,适合连接数目小并且固定架构 |
NIO(NioEndpoint) | IO多路复用 tomcat8之后默认采用该IO模型 NIO方式适合连接数多并且连接比较短的架构 |
AIO(Nio2Endpoint) | 异步非阻塞式IO 启动时执行处理连接方法,此时直接返回 当发生连接事件时,执行回调方法完成连接, 然后执行处理读事件方法,也是直接返回 当发生读事件时,执行对应的回调方法 适用于连接数较多且连接事件较长的应用 |
APR(AprEndpoint) | Apache Portable Runtime,是Apache HTTP服务器的支持库 AprEndpoint是通过JNI调用APR本地库而实现非阻塞IO的 使用需要编译安装APR库 |
Linux内核没有很完善地支持异步IO模型
因此JVM并没有采用原生的Linux异步IO,而是在应用层面通过epoll模拟了异步IO模型
所以在Linux平台上,Java NIO和Java NIO2底层都是通过epoll来实现的
4 Tomcat I/O模型选型
- IO调优实际上是连接器类型的选择
- 一般情况默认都是NIO
- 当web应用启用TLS加密传输并且对性能要求极高时,考虑使用APR
- APR是通过openssl来处理TLS握手和加解密的,openssl本身采用c语言开发,并且对TLS通信做了优化,所以性能比java要高的
- 如果tomcat运行在windows平台,并且http请求的数据量比较大,考虑采用NIO2
- windows从操作系统平面实现了真正意义上的异步IO,如果传输的数据量较大时,异步IO的效果就能显现出来
- 当tomcat运行在linux平台上时,建议使用NIO,在linux平台上nio和nio2都是通过epoll来实现的,但是nio更简单高效
- 指定IO模型时修改Connector标签的protocol属性
5 Tomcat NIO实现
- tomcat中Endpoint组件的主要工作就是处理I/O
- NioEndpoint利用java NIO API实现了多路复用I/O模型
- NioEndpoint是基于主从Reactor多线程模型设计的
- LimitLatch是连接控制器,负责控制最大连接数,默认是8192,当连接数达到最大是阻塞线程,直到后续组件处理完一个连接后将连接数减1
- 到达最大连接数后操作系统底层还是会接受客户端连接,但是用户层已经不在接收
- Acceptor跑在一个单独的线程里,在死循环内调用acceptor方法接收新连接,一旦有新的连接请求到来,accept方法返回一个Channel对象,将Channel帝乡交给Poller去处理
- Poller也跑在单独的线程,Poller内部维护一个Selector,将Acceptor传递过来的Channel注册到Selector读事件,一旦发生读事件,就生成一个SockeProcessor任务对象扔给Executor处理
- Executor就是线程池,负责运行SockeProcessor任务类,SockeProcessor的run方法中会调用Http11Processor来读取和解析请求数据,Http11Processor是应用层协议的封装,它负责调用容器获得响应并将响应通过Channel写出
6 Tomcat异步IO实现
- NIO和NIO2最大的区别是NIO2时异步的
- 异步不需要应用程序自己去触发数据从内核空间到用户空间的拷贝
- NioEndPoint中没有Poller组件,也就是没有Selector
- 在异步I/O模式下,Selector的工作交给内核来做了