使用 NIO 连接器部署到 Tomcat 时,使用 Servlet 3.0 异步是否冗余?

Joe*_*Joe 5 tomcat servlet-3.0

我看到了这个线程:Java - Async in Servlet 3.0 vs NIO in Servlet 3.1但它似乎是关于 Servlet 3.1 NIO(而不是 Tomcat NIO HTTP 连接器)。

我的理解是,使用 NIO HTTP 连接器实现(Tomcat 8 及更高版本中的默认设置)配置 Tomcat,处理请求和产生响应的实际工作是在单独的工作线程上完成的,而轮询线程读取/写入数据保持畅通。

这似乎与 Async Servlet 3.0 解决的问题相同,因为在请求/响应上完成的工作是在独立于 http 连接线程的工作线程上完成的。

那么它们是同一问题的两种解决方案吗?换句话说,如果 servlet 容器已经是异步的,那么以异步方式编写我的代码有什么好处吗?

Sha*_*dra 6

通过了解在从容器到应用程序代码的请求处理过程中的不同点发生 IO 的潜在位置,可以更容易地理解这一点。容器连接器(BIO / NIO)的工作是接受套接字连接并将其交给线程,线程在某个时间点调用 Servlet GET/POST 方法。现在 Tomcat NIO 连接器基本上是容器决定使用 Java NIO 工具(Selector / Channel)以较少线程处理多个 IO 通道。Selector提供一种机制来监视一个或多个 NIO 通道并识别一个或多个何时可用于数据传输,因此选择器容器可以使用一个线程而不是多个线程来管理多个通道。然后这些就绪通道由线程提供服务,这些线程的数量可能少于 BIO 连接器所需的数量。

顺便说一句 - 有在此级别完成的操作系统级别优化以改善 NIO 功能。例如,Java 附带了一个java.nio.channels.SelectorProvider基于 Linux epoll 事件通知工具的实现。该epoll工具在 Linux 2.6 和更新的内核中可用。当有数千个 SelectableChannel 注册到 Selector 时,新的基于 epoll 的 SelectorProvider 实现比传统的基于轮询的 SelectorProvider 实现更具可扩展性。当检测到 2.6 内核时,将默认使用新的 SelectorProvider 实现。当检测到 2.6 之前的内核时,将使用基于轮询的 SelectorProvider。

现在回到手头的问题。在 Servlet 3.0 之前,整个 servlet 处理是同步的,这在 Servet 3.0 中得到了改进,因此 GET/POST 方法现在立即返回但不会写入响应,除非它被调用认为完成AsyncContext complete. 到现在为止还挺好。但还有另一个问题。Servlet 处理可能包括读取/写入请求中可用的输入流/输出流。这个 IO 的性质仍然是传统的。Servlet 3.0 允许异步请求处理,但 IO 读/写仍然是老式的,例如,当从客户端以低速读取大请求负载时,线程会阻塞等待数据 - 所以 Servlet 3.1 非阻塞 IO 来救援现在,您可以在数据准备好而不是等待它的线程时对您的读/写逻辑进行回调样式调用。可以在此处查看其在代码中的工作方式。

我们还是要记住数据库IO(如果有的话)仍然是传统的等待IO。该区域由遵循 JDBC API 的数据库驱动程序控制,并且知道有一天他们也会为非阻塞 IO 提供 API。甲骨文已经导致这样的一个举措异步数据库访问它看起来也像是被利用的Java NIO。这将为使整个请求处理非阻塞铺平道路。

此外,Spring 正在完成另一项有前途的工作 -旨在解决此问题的反应式关系数据库连接

  • 总结一下: * NIO 连接器是 Tomcat 中的一个实现细节,它允许更好地共享资源(使用 epoll 通知工具或通过轮询通道) * 不管上述情况,servlet 代码在没有 servlet 3.0 异步的情况下仍然会阻塞。* Servlet 3.1 通过对请求进行非阻塞 IO 对此进行了改进。RE:异步数据库访问,如果阻塞数据库客户端代码位于工作线程中,那不是没有意义吗? (3认同)