2011-12-08 5 views
5

サーブレットAPI 3で定義された非同期処理を使用してCOMETチャットを実装しようとしました。 。Tomcat 7非同期処理が失敗しました - 同時に1つのリクエストしか処理されません

これは私のdoGetメソッドである:、指定されたタイムアウト後にアイテムを取ると、AsyncContextへの応答を送信すること、それについての印刷メッセージを、私はキューに要求項目を入れている、スレッドの実行があります

@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が応答するまでスレッドがブロックされることです。これは、ブラウザで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 [[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] 

それは見ているとして、次の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で設定するのに特別なものは何も見つかりませんでした。だから問題は、なぜそれがすべきではないかということです。

答えて

5

OK、私は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個のタブにロードしようとすると、最初にロードされ、2番目のものよりもロードされます。ブラウザの動作のようですが、サーバ上で何もブロックされません。 3つのブラウザ(Firefox、Chrome、Opera)を開いたとき、3回の接続が一度に処理されました。

サーブレットAPI 3.0で定義されている非同期処理はTomcat 7で動作しますが、ブラウザで複数のタブではなく独自のプログラムでテストする必要があります...複数のタブでCOMETチャットをテストすることも期待通りに動作しません。しかし、実例では、1台のコンピュータでは1つの接続しか開きません。そして、ブラウザの動作はサーバーの欠陥ではありません。

編集 Spring MVCのソリューションは、Webアプリケーションに含まれていた後、非同期処理モードを停止した(web.xmlファイルからのパラメータは無視されていました)。しかし、非同期サポートが行を追加して手動で設定することができます。

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

URLが同じ場合は、ChromeとFirefoxが複数のGETリクエストをシリアル化するように見えることがあります。 Safariはそれをしません。 – Mark

1

サーバーが正しく設定されていると思います。ブラウザをロードしているだけの場合は、ブラウザの動作に問題がある可能性があります。ブラウザでウェブページにアクセスするだけであれば、ブラウザはページ全体を読み込み、それが完了するまでブロックします。非同期要求が完了するまで、ブラウザはロードを終了しません。例えば

あなたはフィドラーのようなツールを使ってメッセージを見ていたならば、私はあなたが以下の(と仮定すると遅延が4である)参照してくださいね期待:あなたは非同期を取り出した場合

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

モードあなたは参照してくださいね:全体の要求は1が非同期であり、もう1つは同期しているにもかかわらず、終了するまでページが完全にロードされません両方の例で

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

を。非同期リクエストを完全に利用するには、よりスマートなクライアントが必要です。 Javascriptやフレックスなど。

つまり、ブラウザをロードするだけで、サーバーが正しいとは言えません。私はFiddlerのようなツールをつかんで、HTTPメッセージが何を伝えているのか正確に見ていきたいと思います。

+0

これは、ブラウザがやっていることですが、私はドキュメントから理解しているによると、サーバはなるように、非同期リクエストを処理するために期待されていますスレッドは解放され、接続は引き続きアクティブになります。つまり、ノンブロッキングI/Oを利用することです。さもなければそれほど意味がありません。私はjquery-streamで同様のコードを使用していましたが、効果はまったく同じでした。デバッグが難しかったです。 –

関連する問題