2011-12-08 26 views
5

Próbowałem wdrożyć czat COMET, używając przetwarzania asynchronicznego zdefiniowanego w Servlet API 3. Nie działało - czat został zablokowany, więc utworzyłem serwlet debugowania, aby przetestować tylko część asynchroniczną .Tomcat 7 Awaria przetwarzania asynchronicznego - tylko jedno żądanie przetworzone jednocześnie

To jest moja metoda 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"); 
} 

Kładę przedmioty zgłoszeń w kolejce, a tam bieg nici, które odbędzie się rzeczy po określonego limitu czasu i wysłać odpowiedź do AsyncContext, wiadomość druk o tym . Problem polega na tym, że wątek jest blokowany do momentu odpowiedzi AsyncContext. To jest to, co jest widoczne w moim dzienniku po zwróceniu 4 strona wczytuje w przeglądarce:

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 [[email protected], 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 [[email protected], 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 [[email protected], 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 [[email protected], message=r69Y4NQsyR1vj0kzUlHssic2x1Yrr6T09IGKjWAH1E6Lz4VhFTy9dQHi5CPeTObyjLLBDlCLEDfiyMUnVkVIEgYG7r47Ak4w30RklhzdEi9nthqdfNkry6nyjircsFPX534NqWjI1LwsrGq5nOa3ZYtfjfPVpGlk4KDmWP11L53YntO3GmptZPKa50gcqj9i, timeout=0] 

Jak to jest widzieć, kolejna metoda doGet jest wywoływana tylko po uprzednim wniosek jest (teoretycznie asynchroniczny) odpowiedział. A więc cała rzecz asynchroniczna w ogóle nie działa! A oto deklaracja 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> 

Robię wszystko, co można znaleźć w Internecie. Nie widzę miejsca popełnienia błędu. Nie znalazłem nic specjalnego do skonfigurowania w servlet.xml. Pytanie brzmi: dlaczego nie działa tak, jak powinno?

Odpowiedz

5

OK, jako część badań napisałem program testujący, który otworzył wiele połączeń z tomcat i zrobił GET/POST na asynchronicznym serwletu. Mam debugowany i ponownie sprawdzić moją konfigurację server.xml, ograniczonej puli wątków dla lepszej widoczności wyników badań itp Teraz moja konfiguracja złącza wygląda tak:

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

I to działa! Zrobiłem test za pomocą NIO i wykonałem 1000 połączeń naraz i wszystkie zostały przetworzone w jednym czasie.

Jednak efekt, który opisałem, nadal istnieje w przeglądarce. Kiedy próbuję załadować serwlet na 10 kartach, najpierw ładuję się, niż drugi itd. Wygląda to na zachowanie przeglądarki, nic nie zostanie zablokowane na serwerze. Kiedy otworzyłem 3 przeglądarki (Firefox, Chrome, Opera), mam 3 połączenia przetworzone jednorazowo.

Tak więc przetwarzanie asynchroniczne zdefiniowane w Servlet API 3.0 działa na Tomcat 7, jednak musi być przetestowane z własnym programem, a nie z wieloma zakładkami w przeglądarce ... Testowanie czatu COMET na wielu kartach również może nie działać zgodnie z oczekiwaniami. Jednak w rzeczywistym przykładzie jeden komputer otworzy tylko jedno połączenie. A zachowanie przeglądarki nie jest żadnym błędem serwera.

edycja Po ogrzaniu roztworu MVC wiosny włączono do aplikacji internetowych, tryb przetwarzania asynchronicznego zatrzymano (parametr z web.xml był ignorowany). Jednakże wsparcie asynchroniczny można skonfigurować ręcznie poprzez dodanie linii:

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

O dziwo, Chrome i Firefox wydają się serializować wiele żądań GET, jeśli adres URL jest taki sam. Safari tego nie robi. – Mark

1

Myślę, że masz poprawnie skonfigurowany serwer. Jeśli dopiero ładujesz przeglądarkę, problem może wynikać z działania Twojej przeglądarki. Jeśli po prostu uzyskasz dostęp do strony internetowej za pomocą przeglądarki, przeglądarka spróbuje załadować całą stronę i zablokować, aż do jej zakończenia. Twoja przeglądarka nie zakończy ładowania dopóki nie zakończy się żądanie asynchroniczne.

Na przykład, jeśli były, aby spojrzeć na wiadomości z narzędzia jak Skrzypek będę oczekiwać, że pojawi się następujący (zakładając opóźnienia jest 4):

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

Jeśli wyjął asynchronicznie tryb chcesz zobaczyć:

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

W obu przypadkach strona nie zostanie w pełni załadowana, dopóki cały wniosek zostanie zakończona, choć jeden jest asynchroniczne i jeden jest synchroniczny. Aby w pełni wykorzystać asynchroniczne żądania, potrzebujesz inteligentniejszego klienta, np. JavaScript lub flex lub coś takiego.

Innymi słowy, nie sądzę, że można powiedzieć, że serwer jest poprawny, czy nie, po prostu ładowanie za pomocą przeglądarki. Chwyciłbym narzędzie takie jak Fiddler i dokładnie zobaczyłem, na co przechodzą wiadomości HTTP.

+0

To właśnie przeglądarka robi, ale według mam rozumieć z dokumentacją, oczekuje się, że serwer może obsłużyć żądania transmisji asynchronicznej w taki sposób, że wątek zostanie zwolniony, a połączenie pozostanie aktywne. Innymi słowy, aby wykorzystać nieblokujące wejścia/wyjścia. W przeciwnym razie nie miałoby to tyle sensu. Używałem podobnego kodu z jquery-stream, ale efekt był dokładnie taki sam, tylko debugowanie było trudne. –

Powiązane problemy