tomcat BIO与NIO最大区别

  |   4 评论   |   901 浏览

对于TOMCAT来说,NIO与BIO实际并没有太大的区别. 原因在于Servlet规范导致了整体的协议处理都基本是阻塞读的. 除了Header部分以及长链接中的连接复用时的read next request等待.

在tomcat的NIO中, 最终的body数据读取还是到了HttpServletInputStream类似这样的流式读取. 这样tomcat内部还得模拟阻塞读的方式来完成NIO到BIO类型的适配.(实现方式是通过poller线程,或者说是select线程(这个是早期的实现)与httpworker线程的同步).
image.png

图片来源: https://tomcat.apache.org/tomcat-8.5-doc/config/http.html

所以最大的区别就是以上的两点.

  1. NIO模型下,由于header部分的接收与解析这个涉及到协议和内容的解析.同时大小不大. 并且与body等用户关心部分的处理耦合很低. 这样tomcat可以在进行协议解析和header处理的同时都由tomcat自身来处理. 这样可以最大限度的利用NIO的特性. 减少阻塞. (但是实际并没有提升多少)
  2. 另外就是HTTP/1.1 的长链接复用的时候. 这个大家见得最多的一张图就是官方的一个bio对于next Request的处理. 图中有说明BIO的next Request Read 是阻塞的.而NIO的读是非阻塞的. 这个是 TOMCAT的BIO和NIO的最大的区别.

原因在于:
BIO的时候,由于链接已经建立. 读取下一个请求的数据的时候又不能非阻塞.
因此在长链接的时候等待下一个请求的时候,必定会占用一个线程.
Tomcat的处理是直接使用了HttpWorkerThreadPool来处理处理.
表现出来就是Tomcat 在BIO模型下的 HTTP/1.1的 下一个请求读是阻塞并且占用线程的.
这个在极端情况下. 特别在于没有Nginx此类的反向代理处理的时候. 会有大量的线程可能处于BIO的 next Request read 阻塞等待中.

这个影响就是就是在可能存在大量的请求处理一次后.这个线程并不能及时释放(比如HTTP/1.1长链接的超时时间为10秒.但是接下来的10秒时间可能不传输数据了).
从而增大了对HTTP线程池的需求.

而对于NIO,刚好能够较好的规避这个问题. 上面的阻塞读下一个请求本身的预期是要有数据.但是极有可能没有数据了. 因此最好是用nio这样的select线程统一就处理了.
而httpworker线程可以及时释放出来做其它的请求.

上面为什么会强调中间没有nginx的反向代理处理. 这个其实是有原因的.
在有nginx的反向代理后.一个http连接的复用率就会提高了. 而不是与c端的用户一一对应.
nginx与tomcat的连接这个与用户是无关的. 他是可以用来高效的反复利用的. 这样就可以极大的缓解BIO对线程的浪费的问题.
或者说nginx可以用短链接方式与upstream进行连接.

这样的话彻底没有了BIO的毛病. 同时NGINX与tomcat在内网环境. 一次一个链接也不会增加太多的请求时延. 这个也是在BIO场景下, 早期的nginx的反向代理中有大量的运维喜欢使用短链接来连接tomcat.

评论

  • wpp @wpp 回复»

    因为问题背景有些多,感觉这里交流起来不是很方便

  • wpp @leesonwa 回复»

    知乎私信您了,辛苦回复下,可以加个微信交流吗

  • leesonwa @wpp 回复»

    可以到我知乎私信, 也可以给我发邮件. firfor@sina.cn , 这里直接留言也可以.

  • wpp 回复»

    您好,拜读了您的Tomcat知乎文章,我这边有个线上问题,一直没有解决,想请教您一下,怎么联系?

发表评论


取消