【问题标题】:Tomcat 7 Async Processing failing - only one request processed simultanouslyTomcat 7 异步处理失败 - 仅同时处理一个请求
【发布时间】:2012-01-15 22:08:18
【问题描述】:

我试图使用 Servlet API 3 中定义的异步处理来实现 COMET 聊天。它不起作用 - 聊天被阻止,所以我创建了调试 servlet 来仅测试异步部分。

这是我的 doGet 方法:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    log.debug("doGet called");
    int timeout = 30 + RandomUtils.nextInt(60);
    String message = RandomStringUtils.randomAlphanumeric(50 + RandomUtils.nextInt(250));
    response.setHeader("Access-Control-Allow-Origin", "*");
    final AsyncContext context = request.startAsync();

    synchronized(items) {
        items.add(new RequestItem(context, message, timeout));
    }
    log.debug("doGet created request and finished");
}

我将请求项目放入队列中,并且有一个线程正在运行,它将在指定超时后获取项目并将响应发送到 AsyncContext,打印有关它的消息。问题是,线程被阻塞,直到 AsyncContext 得到响应。这是在浏览器中请求 4 个页面加载后在我的日志中可见的内容:

2011-12-08 13:56:36,923 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:56:36,952 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 13:57:39,934 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@175870a, message=zEQpATavzwFl6qIbBKve4OzIY9UUuZBwbqN1TC5KpU3i8LM9B6ChgUqaRmcT2yF, timeout=0]
2011-12-08 13:57:39,962 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:57:39,962 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 13:58:53,949 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@88ee03, message=pKHKC632CPIk7hGLV0YqCbQl1qpWIoyNv5OWCp21bEqoni1gbY79HT61QEUS2eCjeTMoNEwdqKzCZNGgDngULysSzVdzFTnQQ5cQ8JvcYnp1pLVqGTueJPWnbRdUuO, timeout=0]
2011-12-08 13:58:53,960 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:58:53,960 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 13:59:36,954 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@197950e, message=43FPeEUZWBLqgkAqS3WOFMiHUMVvx6o4jNqWLx8kUvwxqJqpOZyGCtiIcr7yw, timeout=0]
2011-12-08 13:59:36,999 DEBUG [my.servlet.TestAsyncServlet] doGet called
2011-12-08 13:59:36,999 DEBUG [my.servlet.TestAsyncServlet] doGet created request and finished
2011-12-08 14:00:34,957 TRACE [my.servlet.TestAsyncServlet] respond on item RequestItem [context=org.apache.catalina.core.AsyncContextImpl@1cb1278, message=r69Y4NQsyR1vj0kzUlHssic2x1Yrr6T09IGKjWAH1E6Lz4VhFTy9dQHi5CPeTObyjLLBDlCLEDfiyMUnVkVIEgYG7r47Ak4w30RklhzdEi9nthqdfNkry6nyjircsFPX534NqWjI1LwsrGq5nOa3ZYtfjfPVpGlk4KDmWP11L53YntO3GmptZPKa50gcqj9i, timeout=0]

正如所见,下一个 doGet 方法仅在前一个请求(理论上是异步的)响应后才被调用。所以整个异步事情根本不起作用!这是 web.xml 声明:

  <servlet>
    <servlet-name>TestAsyncServlet</servlet-name>
    <servlet-class>my.servlet.TestAsyncServlet</servlet-class>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestAsyncServlet</servlet-name>
    <url-pattern>/test-async</url-pattern>
  </servlet-mapping>

我正在尽一切可能在互联网上找到。我看不出犯错的地方。我发现在 servlet.xml 中配置没有什么特别之处。所以问题是,为什么它不能正常工作?

【问题讨论】:

    标签: java tomcat asynchronous comet servlet-3.0


    【解决方案1】:

    好的,作为研究的一部分,我编写了测试程序,该程序打开到 tomcat 的多个连接并在异步 servlet 上执行 GET/POST。我已经调试并重新检查了我的 server.xml 配置、有限的线程池以更好地查看测试结果等。现在我的连接器配置如下所示:

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" 
                   minProcessors="3"
                   maxProcessors="8"
                   maxThreads="20"
                   connectionTimeout="150000" 
                   asyncTimeout="150000" />
    

    这是有效的!我用NIO做了测试,一次连接了1000个,一次处理完。

    但是,我所描述的效果,仍然存在于浏览器中。当我尝试在 10 个选项卡上加载 servlet 时,首先加载,然后再加载等等。这似乎是浏览器的行为,服务器上没有任何内容被阻止。当我打开 3 个浏览器(Firefox、Chrome、Opera)时,我一次处理了 3 个连接。

    因此,Servlet API 3.0 中定义的异步处理可以在 Tomcat 7 上运行,但是,它必须使用自己的程序进行测试,而不是在浏览器中使用多个选项卡...在多个选项卡中测试 COMET 聊天也无法按预期工作。然而,在现实生活中,一台计算机将只打开一个连接。而且,浏览器的行为不是任何服务器的错。

    编辑 将 Spring MVC 解决方案包含到 Web 应用程序后,异步处理模式停止(忽略来自 web.xml 的参数)。但是,可以通过添加行手动设置异步支持:

    request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
    

    【讨论】:

    • 奇怪的是,如果 URL 相同,Chrome 和 Firefox 似乎会序列化多个 GET 请求。 Safari 不这样做。
    【解决方案2】:

    我认为您的服务器配置正确。如果您只是使用浏览器加载,那么问题可能出在浏览器的工作方式上。如果您只是使用浏览器访问网页,那么浏览器将尝试加载整个页面并阻止直到完成。在异步请求完成之前,您的浏览器不会完成加载。

    例如,如果您使用 Fiddler 之类的工具查看消息传递,我希望您会看到以下内容(假设延迟为 4):

    Browser -> Server [Time: 0]   Request
    Server -> Browser [Time: 0.1] Async Response
    Server -> Browser [Timer: 4]  Complete Response
    Browser shows page loaded.
    

    如果您取出异步模式,您会看到:

    Browser -> Server [Time: 0] Request
    Server -> Browser [Time: 4] Response
    Browser shows page loaded.
    

    在这两个示例中,页面在整个请求完成之前不会完全加载,即使一个是异步的,一个是同步的。要充分利用异步请求,您将需要一个更智能的客户端,例如Javascript 或 flex 之类的。

    换句话说,我认为您不能仅通过浏览器加载来判断服务器是否正确。我会拿一个像 Fiddler 这样的工具,看看到底是什么 HTTP 消息。

    【讨论】:

    • 这是浏览器正在做的事情,但是根据我从文档中了解到的,服务器应该以这样的方式处理异步请求,即线程将被释放,而连接仍然是积极的。换句话说,利用非阻塞 I/O。否则就没有这么大的意义了。我在jquery-stream中使用了类似的代码,但效果完全一样,只是更难调试。
    猜你喜欢
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    • 2012-09-20
    • 2021-07-13
    相关资源
    最近更新 更多