【tomcat调优系列3】Tomcat底层BIO和NIO实现原理

Tomcat IO选择历史

  1. Tomcat7时默认用的BIO,同步阻塞。可以通过配置修改为NIO
1
2
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Ni oProtocol" 
connectionTimeout="20000" redirectPort="8443" />
  1. Tomcat8.5以后默认用的是NIO.

阻塞与非阻塞

Socket通信过程分两个部分:

  1. 连接准备
  2. 拷贝内核缓存到用户缓存。
    阻塞和非阻塞的概念是在连接准备阶段的描述。

Tomcat的BIO实现

  1. JioEndpoint的Acceptor线程负责循环阻塞接收sock连接。
  2. 每接收到一个socket连接就包装成SocketProcessor扔进线程池Executor.SocketProcessor是一个Runnable
  3. SocketProcess负责从scoket阻塞读取数据,并且向socket中阻塞写入数据。

Acceptor现成数量默认为1,可以通过acceptorThreadCount参数进行配置。

1
2
3
4
5
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" 
maxThreads="150" minSpareThreads="4"/>
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Ni oProtocol"
connectionTimeout="20000"
redirectPort="8443" executor="tomcatThreadPool"/>

Tomcat中每个Connector都会创建一个线程池,并且默认值:

  1. 最小线程数量10
  2. 最大线程数量20

使用BIO处理请求时:

  1. 当请求数量比较大时,可以提高Acceptor线程数量,提高接收请求的速率。
  2. 当请求比较耗时时,可以提高线程池Executor的最大线程数量。

原理图:

图片

Tomcat的NIO实现

NIO非阻塞接收socket连接,非阻塞从socket读取数据,非阻塞将数据写入socket中。

在Tomcat中,只有从socket读取请求行,请求头数据时是非阻塞的。在读取请求体是阻塞的,响应数据也是阻塞的。