本文主要包括Tomcat9的NIO、NIO2、APR三种I/O模型的工作原理以及使用Jmeter对其进行持续压力测试。
1、connector的工作原理
这里我们说的Tomcat中三种不同的I/O模型主要指的是其连接器(connector)的工作模型,对于tomcat而言,连接器一般指的是coyote,其工作原理大致如下图所示:
连接器中的各个组件的作用如下:
1.1 EndPoint
EndPoint
即Coyote通信端点,是通信监听的接口,是具体Socket接收和发送处理器,是对传输层(四层)的抽象,因此EndPoint
用来实现TCP/IP协议的。Tomcat 并没有EndPoint
接口,而是提供了一个抽象类AbstractEndpoint
, 里面定义了两个内部类:Acceptor
和SocketProcessor
。Acceptor
用于监听Socket连接请求。 SocketProcessor
用于处理接收到的Socket请求,它实现Runnable
接口,在Run
方法里 调用协议处理组件Processor
进行处理。为了提高处理能力,SocketProcessor
被提交到线程池来执行,而这个线程池叫作执行器(Executor)。
1.2 Processor
**Processor
是coyote的协议处理接口 。**如果说EndPoint是用来实现TCP/IP协议的,那么 Processor
用来实现HTTP协议,Processor
接收来自EndPoint的Socket,读取字节流解析成Tomcat的Request
和Response
对象,并通过Adapter
将其提交到容器处理, Processor
是对应用层(七层)协议的抽象。
1.3 ProtocolHandler
**ProtocolHandler
是Coyote的协议接口,通过Endpoint和Processor ,实现对具体协议(HTTP或AJP)的处理。**Tomcat 按照协议和I/O 提供了6个实现类 : AjpNioProtocol
, AjpAprProtocol
, AjpNio2Protocol
, Http11NioProtocol
,Http11Nio2Protocol
, Http11AprProtocol
。我们在配置tomcat/conf/server.xml
中的connecter
块时 , 至少要指定具体的ProtocolHandler
, 当然也可以指定协议名称(如HTTP/1.1)。
1.4 Adapter
由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的Request类来存放这些请求信息。ProtocolHandler
接口负责解析请求并生成Tomcat的Request
类。 但是这个Request对象不是标准的ServletRequest,不能用来作为参数来调用容器。因此需要引入CoyoteAdapter
,连接器调用CoyoteAdapter
的Sevice
方法,传入Tomcat的Request
对象,CoyoteAdapter将Request
转成ServletRequest
,再调用容器的Service方法。
2、三种I/O模型原理
在开始之前,我们先看一下tomcat官网给出的这三种I/O模型的工作参数的一个对比图:
这里我们可以看到一般说的NIO、NIO2和APR使用的是非阻塞方式指的就是在读取请求报头和等待下一个请求的时候是使用的非阻塞方式。
Tomcat的NIO是基于I/O复用(同步I/O)来实现的,而NIO2是使用的异步I/O。参考经典书籍《UNIX网络编程 卷1 套接字联网API》,两者的主要原理如下:
I/O复用(NIO)
I/O复用(I/O multiplexing)可以调用select
或poll
,阻塞在这两个系统调用中的某一个之上,而不是阻塞在真正的I/O系统调用上。进程阻塞于select
调用,等待数据报套接字变为可读。当select
返回套接字可读这一条件时,进程调用recvfrom
把所读数据报复制到应用进程缓冲区,尽管这里需要使用select
和recvfrom
两个系统调用,但是使用select
的可以等待多个描述符就绪,即可以等待多个请求。
异步IO(NIO2)
异步I/O(asynchronous I/O)的工作机制是:告知内核启动某个操作,并让内核在整个操作(包括将数据从内核复制到应用程序的缓冲区)完成后通知应用程序。需要注意的是:异步I/O模型是由内核通知应用进程I/O操作何时完成。
最后我们可以把上面的过程结合剩下没有提到的三种UNIX系统中的IO模型进行对比得到下图:
NIO、NIO2和APR的区别
NIO | NIO2 | APR | |
---|---|---|---|
实现 | JAVA NIO库 | JDK1.7 NIO2库 | C |
IO模型 | 同步非阻塞 | 异步非阻塞 | 取决于系统 |
APR的重点在于使用C语言实现并且能够跨平台使用,它相当于将UNIX系统中的IO操作进行了一层封装使得编程开发更容易
3、connector的几个重要参数
connectionTimeout
The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented. Use a value of -1 to indicate no (i.e. infinite) timeout. The default value is 60000 (i.e. 60 seconds) but note that the standard server.xml that ships with Tomcat sets this to 20000 (i.e. 20 seconds). Unless disableUploadTimeout is set to
false
, this timeout will also be used when reading the request body (if any).
在connector和请求的客户端建立连接之后开始计时,当超过该值的时候就会超时,然后断开连接。使用值-1表示无超时,默认值为60000(即60秒),但Tomcat中的server.xml将此值设置为20000(即20秒)。
除非disableUploadTimeout设置为false,否则在读取请求正文(如果有)时也会使用此超时。
maxThreads
The maximum number of request processing threads to be created by this Connector, wh