Servlet异步处理请求

Sow*_*iya 6 java multithreading asynchronous servlets

当我正在探索NodeJS应用程序和Java应用程序如何处理请求时,我遇到了Servlet对请求的异步处理.

从我在不同的地方阅读:

请求将由来自Servlet容器的HTTP线程接收和处理,并且在阻塞操作(如I/O)的情况下,请求可以移交给另一个Threadpool,并且接收请求的HTTP线程可以返回接收并处理下一个请求.

现在,来自Threadpool的工作人员将占用耗时的阻塞操作.

如果我理解的是正确的,我有以下问题:

即使是处理阻塞操作的线程也会等待该操作完成,从而阻塞资源(并且处理的线程数等于内核数),如果我是对的话.

通过使用异步处理,这里获得了什么?

如果没有,请赐教.

ver*_*tas 5

我可以用 Node.js 来解释它的好处(同样适用于其他地方)。

问题。阻塞网络 IO。

假设您想与服务器创建一个连接,为了从连接中读取数据,您将需要一个线程 T1,它将通过网络读取该连接的数据,此读取方法是阻塞的,即您的线程将无限期地等待,直到有任何数据读书。现在假设此时您有另一个连接,现在要处理此连接,您必须创建另一个线程 T2。该线程很可能会再次被阻止读取第二个连接上的数据,因此这意味着您可以处理与系统中的线程一样多的连接。这称为“每个请求线程模型”。由于大量的上下文切换和调度,创建大量线程会降低系统性能。该模型的扩展性不好。

解决方案 :

一点背景知识,FreeBSD/Linux 中有一种称为 kqueue/epoll 的方法。这两种方法都接受 socketfd 列表(作为函数参数),调用线程会被阻塞,直到一个或多个套接字准备好读取数据,并且这些方法返回这些就绪连接的子列表。参考号 http://austingwalters.com/io- Multiplexing/

现在假设您对上述方法有了一定的了解。想象一下,有一个名为 EventLoop 的线程,它调用上述方法 epoll/kqueue。

所以在java中你的代码看起来像这样。

 /*Called by Event Loop Thread*/

while(true) {

   /**
     * socketFD socket on which your server is listening
     * returns connection which are ready 
     */ 
    List<Connection> readyConnections = epoll( socketFd );

   /** 
     * Workers thread will read data from connection
     * which would be very fast as data is already ready for read
     * So they don't need to wait.
     */ 
     submitToWorkerThreads(readyConnections); 

   /**
     * callback methods are queued by worker threads with data
     * event loop threads call this methods
     * this is where the main bottleneck is in case of Node.js
     * if your callback have any consuming task lets say loop 
     * of 1M then you Event loop will be busy and you can't 
     * accept new connection. In practice in memory computation 
     * are very fast as compared to network io.
     */
     executeCallBackMethodsfromQueue();     
   }
Run Code Online (Sandbox Code Playgroud)

所以现在您看到上面的方法可以接受比每个请求线程模型更多的连接,而且工作线程也不会被卡住,因为它们只会读取那些有数据的连接。当工作线程读取整个数据时,它们将使用您在侦听时提供的回调处理程序将响应或数据排队到队列中。该回调方法将再次由事件循环线程执行。

上述方法有两个缺点。

  1. 无法正确使用多处理器的所有核心。
  2. 长时间内存计算会显着降低性能。

第一个缺点可以通过 Clustered Node.js 来解决,即与 cpu 的每个核心对应的一个 Node.js 进程。

无论如何,看看 vert.x,它有点类似 node.js,但用的是 java。还可以探索 Netty。


Kon*_*hov 1

是的,在这种情况下,阻塞操作将在它自己的线程中执行,并且会阻塞一些资源,但是您的 HTTP 线程现在可以自由地处理一些其他可能不那么耗时的操作。

异步处理的好处是能够在等待重量级操作响应时继续处理其他请求,而不是愚蠢地阻塞 HTTP 线程。