Tomcat IO模型

  1. BIO
  2. NIO 与 Servlet 异步
  3. NIO 与 HTTP 服务调用
  4. 总结

BIO

在 Tomcat6.X 版本对 NIO 提供比较完善的支持之前,作为 Web 服务器,Tomcat 以 BIO 的方式接收并处理客户端的 HTTP 请求,当并发访问量比较大时,就容易发生拥塞等性能问题,它的工作原理示意如下所示:

传统同步阻塞通信(BIO)面临的主要问题如下:

性能问题:一连接一线程模型导致服务端的并发接入数和系统吞吐量受到极大限制。

可靠性问题:由于 I/O 操作采用同步阻塞模式,当网络拥塞或者通信对端处理缓慢会导致 I/O 线程被挂住,阻塞时间无法预测。

可维护性问题:I/O 线程数无法有效控制、资源无法有效共享(多线程并发问题),系统可维护性差。

从上图我们可以看出,每当有一个新的客户端接入,服务端就需要创建一个新的线程(或者重用线程池中的可用线程),每个客户端链路对应一个线程。当客户端处理缓慢或者网络有拥塞时,服务端的链路线程就会被同步阻塞,也就是说所有的 I/O 操作都可能被挂住,这会导致线程利用率非常低,同时随着客户端接入数的不断增加,服务端的 I/O 线程不断膨胀,直到无法创建新的线程。

同步阻塞 I/O 导致的问题无法在业务层规避,必须改变 I/O 模型,才能从根本上解决这个问题。

Tomcat 6.X 提供了对 NIO 的支持,通过指定 Connector 的 protocol=“org.apache.coyote.http11.Http11NioProtocol”,就可以开启 NIO 模式,采用 NIO 之后,利用 Selector 的轮询以及 I/O 操作的非阻塞特性,可以实现使用更少的 I/O 线程处理更多的客户端连接,提升吞吐量和主机的资源利用率。Tomcat 8.X 之后提供了对 NIO2.0 的支持,默认也开启了 NIO 通信模式。

NIO 与 Servlet 异步

事实上,Tomcat 支持 NIO,与 Tomcat 的 HTTP 服务是否是异步的,没有必然关系,这个可以从两个层面理解:

HTTP 消息的读写:即便采用了 NIO,HTTP 请求和响应的消息处理仍然可能是同步阻塞的,这与协议栈的具体策略有关系。从 Tomcat 官方文档可以看到,Tomcat 6.X 版本即便采用 Http11NioProtocol,HTTP 请求消息和响应消息的读写仍然是 Blocking 的。

HTTP 请求和响应的生命周期管理:本质上就是 Servlet 是否支持异步,如果 Servlet 是 3.X 之前的版本,则 HTTP 协议的处理仍然是同步的,这就意味着 Tomcat 的 Connector 线程需要同时处理 HTTP 请求消息、执行 Servlet Filter、以及业务逻辑,然后将业务构造的 HTTP 响应消息发送给客户端,整个 HTTP 消息的生命周期都采用了同步处理方式。

NIO 与 HTTP 服务调用

HTTP 请求消息的读取、Servlet Filter 的执行、业务 Servlet 的逻辑处理,以及 HTTP 响应都是由 Tomcat 的 NIO 线程(Processor,实际更复杂些,这里做了简化处理)做处理,即 HTTP 消息的处理周期中都是串行同步执行的,尽管 Tomcat 使用 NIO 做接入,HTTP 服务端的处理仍然是同步的。它的弊端很明显,如果 Servlet 中的业务逻辑处理比较复杂,则会导致 Tomcat 的 NIO 线程被阻塞,无法读取其它 HTTP 客户端发送的 HTTP 请求消息,导致客户端读响应超时。

可能有读者会有疑问,途中标识处,为什么不能创建一个业务线程池,由业务线程池异步处理业务逻辑,处理完成之后再填充 HttpServletResponse,发送响应。实际上在 Servlet 支持异步之前是无法实现的,原因是每个响应对象只有在 Servlet 的 service 方法或 Filter 的 doFilter 方法范围内有效,该方法一旦调用完成,Tomcat 就认为本次 HTTP 消息处理完成,它会回收 HttpServletRequest 和 HttpServletResponse 对象再利用,如果业务异步化之后再处理 HttpServletResponse,拿到的实际就不是之前请求消息对应的响应,会发生各种非预期问题,因此,业务逻辑必须在 service 方法结束前执行,无法做异步化处理。

如果使用的是支持 Servlet3.0+ 版本的 Tomcat,通过开启异步处理模式,就能解决同步调用面临的各种问题,在后续章节中会有详细介绍。

总结

通过以上分析我们可以看出,除了将 Tomcat 的 Connector 配置成 NIO 模式之外,还需要 Tomcat 配套的 Servlet 版本支持异步化(3.0+),同时还需要在业务 Servlet 的代码中开启异步模式,HTTP 服务端才能够实现真正的异步化:I/O 异步以及业务逻辑处理的异步化。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 wshten@gmail.com

文章标题:Tomcat IO模型

本文作者:KevinTen

发布时间:2019-09-15, 00:00:00

最后更新:2019-09-15, 17:40:01

原始链接:http://github.com/kevinten10/2019/09/15/Tomcat/Tomcat-IO模型/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

csdn zhihu github