【问题标题】:What is the benefit of Async Servlets异步 Servlet 有什么好处
【发布时间】:2015-01-27 12:37:28
【问题描述】:

我正在阅读 Async servlets 3.1

据说当有很多耗时的操作要完成时,发送请求的线程会被释放,例如从数据库中获取一长串数据。

我无法理解这里的好处,因为无论如何都会分配一个新线程来处理数据库连接和响应处理,即使负责请求的初始线程已被释放。

那么,Async servlet 如何比我们之前使用的每个请求线程模型更有益。

【问题讨论】:

    标签: jakarta-ee servlet-3.1


    【解决方案1】:

    只有这么多线程可用于服务 HTTP 请求。这些来自 HTTP 线程池,可通过您的应用程序服务器配置机制(例如 Glassfish 的管理 UI)进行配置。如果您的 servlet 执行长时间运行的操作,这些请求线程将被占用。一旦所有池化的请求线程都被占用,在一个被释放之前,将无法处理更多的请求。

    使用异步 servlet,请求线程将返回到池中,而不是在非异步情况下被长时间运行的同步操作阻塞。

    【讨论】:

    • 但是异步操作不像例如从数据库中检索数据将消耗一个新线程来释放一个服务 HTTP 请求的线程
    • 是的,它将使用线程进行异步操作。很有可能它使用的线程也将被管理和池化,例如通过托管执行器资源或池化 EJB。 Async Servlet 的好处是提高 Web 应用程序在空闲容器请求线程方面的可伸缩性。
    • @kapilchhattani But isnt the Async operation like for e.g. Data Retrieval from DB going to consume a new thread - 是的,这是一个真正的风险。如果您不小心,您只会将一个线程换成另一个线程。如果 HTTP 线程和异步处理线程都来自一个池(通常是这种情况),那么您可以很好地为 HTTP 池分配更多线程,因为最终效果将毫无意义。
    • @ArjanTijms 你是完全正确的!如果您正在使用嵌入式服务器,那么使用 AsyncServlet 模型是没有意义的(或者至少我还没有找到它),因为您始终可以调整总 HTTP 线程池。但是,如果您在提供的无法配置的 servlet 容器中运行应用程序,情况就完全不同了。在这种情况下,AsyncModel 非常有用。
    【解决方案2】:

    这里分两部分回答:

    1. Async servlet 如何比我们之前的每个请求线程模型更有益:这种模型早已失效,几乎所有 Java 服务器都使用 NIO,它允许这些服务器使用少数几个线程来处理数百个连接线程。您也可以为您的应用服务器验证这一点,您会惊喜地发现它确实使用 NIO :)。异步 Servlet 与每个线程一个请求没有任何关系。
    2. 那么为什么异步 Servlets:嗯,Async Servlets 允许完成 原始 请求,而无需等待异步任务完成(希望是长期运行)。因此,远程客户端可以立即响应,如果需要,他们可以做一些其他的事情。服务器稍后可以在其中一个线程中处理异步任务。这些异步操作通常在单独的线程池中完成,用于异步操作。用于处理客户端连接的线程池用于异步操作。

    更新:如果我们已经在使用 NIO 线程池,为什么需要 Async Servlets 的更多细节 不久前,我确实在http://manish-m.com/?p=996 上记下了关于非阻塞 IO 的笔记。您还可以在http://manish-m.com/?p=915 上查看相关帖子(尤其是此页面上的 IO Playground 部分)。

    NIO 线程池用于处理多个连接请求。它利用内核的非阻塞 IO 特性,使得少量线程可以处理多个连接。

    但是,从网络缓冲区读取数据的线程也会执行“用户代码”(我们在 servlet 中编写的代码)。 NIO 的 servlet 容器框架处理接受客户端请求,但它不能自己处理由我们编写的“阻塞用户代码”。因此,如果我们编写一个需要 10 秒的 DB 查询,那么容器框架无法自行异步处理它。我们将通过在 servlet 中编写任何阻塞代码来阻塞原始 NIO 线程池。因此,我们需要显式编写任何我们认为可能会阻塞容器的请求线程的内容,作为 Java EE 中的异步 servlet。

    同样,当我们使用 Netty、MINA 等其他 NIO 框架时,我们需要注意确保代码“不会”阻塞处理网络连接的 NIO 线程。这通常通过将如此长时间运行的任务卸载到另一个线程池来实现(这是容器在您编写异步 servlet 时所做的事情)。

    【讨论】:

    • WRT 到上面的#1 我认为你混淆了 NIO 的工作方式是哪些线程在起作用。即使使用 NIO 实现其选择器功能的服务器也可以并且仍然会实现一个线程池来处理从应用程序服务器传递到应用程序的每个请求的线程(例如,异步 servlet)。例如看到这个灰熊的 NIO 连接器架构的解释jfarcand.wordpress.com/2006/01/26/…
    • @NBW 不确定您指的是文章的哪一部分。我在 Grizzly 架构页面中读到的是 - “这种策略可以防止每个请求一个线程,并使 Grizzly 能够仅用 30 个线程为超过 10 000 个并发用户提供服务”。你能指出文章中的具体部分吗?
    • Grizzly 正在使用 NIO 处理低级 IO。该层独立于上层,例如异步 servlet 所属的 servlet 容器。在两者之间有一个请求线程池,作为容器资源进行管理,每个请求有 1 个线程。在处理其长时间运行的请求时,Async servlet 允许释放这些线程,从而允许 Web 应用程序更好地扩展。
    • @NBW 同意,这就是我在回答 #2 中试图阐明的内容“这些异步操作通常在单独的线程池中完成,用于异步操作。” :) 但是,只有异步操作使用单独的线程池。其他非异步 servlet 在基本 NIO 线程池中运行,您可以通过在 servlet 代码中执行“阻塞”操作(不使用 Async Servlet API)轻松耗尽它们。
    • #1 只适用于静态文件、comet 和 web socket。对于静态文件,Web 服务器可以使用带有 MMAP/DMA 的 sendfile,零复制!对于 Comet 和 Web 套接字应用程序,编程模型是异步的并且很好地映射到 NIO API,这很酷!对于 servlet,这是一个完全不同的故事。例如。 Tomcat,endpoint处理器在你的servlet之前只解析header,但是post body在你的servlet的控制下,getInputStream由底层的InternalNioInputBuffer桥接,虽然是NIO但它仍然是阻塞的,只是为了满足servlet规范。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 1970-01-01
    • 2019-10-21
    • 2019-07-04
    • 1970-01-01
    • 2014-02-09
    相关资源
    最近更新 更多