Сбой асинхронной обработки Tomcat 7 - одновременно обрабатывается только один запрос - PullRequest
5 голосов
/ 08 декабря 2011

Я пытался реализовать чат COMET с использованием асинхронной обработки, определенной в Servlet API 3. Он не работал - чат заблокирован, поэтому я создал отладочный сервлет для проверки только асинхронной части.

Это мой метод 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. Поэтому вопрос в том, почему он не работает так, как должен?

Ответы [ 2 ]

5 голосов
/ 09 декабря 2011

ОК, в рамках исследования я написал программу тестирования, которая открывала несколько соединений с tomcat и выполняла 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 вкладках, сначала загружается, потом второй и т. Д. Это похоже на поведение браузера, на сервере ничего не блокируется.Когда я открыл 3 браузера (Firefox, Chrome, Opera), я обработал 3 соединения за один раз.

Таким образом, асинхронная обработка, определенная в Servlet API 3.0, работает на Tomcat 7, однако ее необходимо протестировать с собственной программой, а не с несколькими вкладками в браузере ... тестирование чата COMET на нескольких вкладках также может не работать, так какожидается.Однако в реальном примере один компьютер откроет только одно соединение.И поведение браузера не является ошибкой любого сервера.

edit После включения решения Spring MVC в веб-приложение режим асинхронной обработки был остановлен (параметр из web.xml был проигнорирован).Однако асинхронную поддержку можно настроить вручную, добавив строку:

request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
1 голос
/ 08 декабря 2011

Я думаю, что ваш сервер настроен правильно. Если вы просто загружаете браузер, то проблема может заключаться в том, как работает ваш браузер. Если вы просто заходите на веб-страницу с помощью браузера, браузер попытается загрузить всю страницу и заблокировать ее до тех пор, пока она не будет завершена. Ваш браузер не завершит загрузку, пока не будет завершен асинхронный запрос.

Например, если бы вы смотрели на сообщения с помощью такого инструмента, как 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-сообщения.

...