Tomcat的作用思考及NIO的应用(要区分JavaNIO和操作系统的NIO模型)

编程

Tomcat的作用

  平时写完web程序都是直接点击启动,就可以在本机浏览器访问了。但是仔细想想,我们似乎都没有写过浏览器与servlet通信的代码,也没有写过创建request、reponse的代码。实际上,这些都是由Tomcat完成的,它的主要作用如下:

  1. 完成服务的与客户端的数据收发,即通信功能。

  2. 完成请求的映射功能。

  3. 管理servlet的生命周期。

Tomcat的工作模型(图片来源于网络):

 

connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化;  Container用于封装和管理Servlet,以及具体处理Request请求;

 一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但是可以有多个Connectors,这是因为一个服务可以有多个连接,如同时提供Http和Https链接,也可以提供向相同协议不同端口的连接。为了方便,Engine可以直接看成我们编写的服务器程序,即servlet。

Tomcat的BIO工作模型

  客户端与服务端建立的TCP连接,线程在等待其对应的客户端连接发送数据时是不能做其它事的,一直在阻塞中。也因此有N个客户端与服务端建立了连接,就必须要N条线程去处理。工作模型如下:

 

实际上的Connector组件里面还有很多组件,这里做简化,理清工作模式。

 

Tomcat的NIO工作模型

   这里的NIO是指Java的IO库(New IO),与BIO不同。简单说:服务端有一条(或几条)线程专门轮询每条连接是否有数据收发,发现有的话,就从线程池中选出一条工作线程来执行。即某连接有输入或输出要求时才用一条线程去处理否则不管这个连接,这样就避免了因为等待socket的数据而导致线程阻塞。工作模型:

总结NIO与BIO:BIO中,socket没有数据收发时线程不能干其他事,进入阻塞; NIO中,socket没有数据收发时没有线程去管它,因此不会有线程阻塞。实际情况中,建立了连接后有数据收发的时间占比很少,因此NIO可以大幅降低线程的空闲时间从而大大提升服务器性能。

  注意:其实BIO、NIO是描述操作系统的IO模型的,这里的NIO其实应该叫New IO表示Java的新IO库。但是这个新IO库又能体现Non Blocking IO做法,因此很多地方误把这个新的Java IO库也叫做非阻塞式IO。要注意与操作系统NIO模型的区别(Java的New IO库底层不是用操作系统的NIO模型实现的,而是用IO多路复用模型实现的,linux中IO多路复用模型的核心就是epoll方法)。操作系统的NIO仅仅是指线程调用read函数读取数据时如果数据没有准备就绪直接返回失败,不进入阻塞,将描述符设置为非阻塞即可使用此模型。多路复用则属于一种更高效的调度机制,基础是建立在NIO模型之上,增加了轮询线程负责多个描述符、事件通知等机制。

 

简单总结下IO多路复用:IO多路复用建立在非阻塞IO的基础上,具体做法:

1. 使用一条线程监视多个socket(即socket描述符,需要将他们提前注册到可查询的表里,这个表的实际实现是红黑树);

2. 调用epoll去表里面查询(实际是遍历红黑树)哪些socket可以读写了,在找到符合条件的socket之前,调用epoll的线程是阻塞的;

3. 调用read把socket接收到的数据复制到线程里,因为socket接收的数据会经过网卡然后放到内核态缓冲区里,所以使用前需要将数据复制到用户态缓冲区。这个过程也是阻塞的。

4. 在将数据复制到用户态缓冲区后,线程就可以开心的拿着别人发来的数据正常工作了。

可以看出,非阻塞式IO其实有两步还是阻塞的。之所以叫非阻塞是因为:除了轮询线程不会有工作线程因为socket没数据收发而在阻塞,socket没数据收发根本不会有工作线程去处理;这样就减少了大量的阻塞时间,轮询查看socket是否有数据收发的时间、socket有了数据收发后数据在内核与用户之间的复制发生的阻塞所占的时间相比而言占比很小。

以上是 Tomcat的作用思考及NIO的应用(要区分JavaNIO和操作系统的NIO模型) 的全部内容, 来源链接: utcz.com/z/518405.html

回到顶部