9

これは私の最初のSOの質問なので、しばらくお待ちください:)

次のサービスを作成しようとしています。

  1. 照会する URL を含む HTTP GET 要求を受け取ります
  2. 単一の GET 要求の場合、サービスは URL を抽出します
  3. URL についてローカル DB にクエリを実行します
  4. DB で結果が見つかった場合はそれをクライアントに返します。そうでない場合は、いくつかの外部サービスにクエリを実行する必要があります (応答に比較的長い時間がかかる場合があります)。
  5. URL の結果をクライアントに返す

私はこれを仮想マシンと Tomcat7 with spring で実行しています。前もってお詫び申し上げます。私は Tomcat の初心者です。

とにかく、私はこのサービスに対して多くの同時 GET リクエスト (数十万の同時リクエスト) を期待しています.数十万の同時リクエストを処理できるサービス)

サービス、特にTomcatでの非同期リクエストの処理について多くのことを読んできましたが、まだ不明な点がいくつかあります:

  1. Tomcat の公式 Web サイトから、Tomcat には多数のアクセプター スレッドと多数の作業スレッドが含まれているようです。その場合、なぜ AsyncContext を使用する必要があるのでしょうか? Tomcat の作業スレッドを解放し、アプリケーションで別のスレッドを占有してまったく同じアクションを実行する利点は何ですか? (システムにはまだ 1 つのアクティブなスレッドがあります)
  2. 最初の質問と似ていますが、AsyncContext を作成して別のスレッドで使用する利点はありますか? (私のアプリケーションで作成されたスレッド プールからのスレッド)
  3. 同じ問題に関して、Callable または DeferredResult を返して、Tomcat のスレッドまたは自分のスレッドのいずれかで処理できることをここで確認しました。Callable を返すか、リクエストから AsyncContext を処理するだけで DeferredResult を使用する利点はありますか?
  4. また、callable を返すことにした場合、Tomcat はどのスレッド プールから呼び出し可能オブジェクトを処理するスレッドを取得しますか? ここで使用されているスレッドは、前に述べた Tomcat の作業スレッドと同じですか? その場合、Tomcat の作業スレッドを 1 つ解放し、代わりに別のスレッドを使用すると、どのようなメリットがありますか?
  5. Oracle のドキュメントから、同時に処理される Runnable オブジェクトを AsyncContext に渡すことができることがわかりました。この Runnable を実行するために使用されるスレッドはどこから来るのですか? 私はそれを制御できますか?また、AsyncContext を自分のスレッドの 1 つに渡すだけでなく、AsyncContext を Runnable に渡す利点はありますか?

同じことについて何度も質問して申し訳ありませんが、私と私の同僚はこれらのことについて 1 週間以上論争していますが、具体的な答えはありません。

もう 1 つ一般的な質問があります。私が説明したサービスをスケーラブルにするための最良の方法は何だと思いますか? (現時点でマシンを追加することは別として)、目的のソリューションの例や参照を投稿できますか?

見ているリンクのリンクをもっと投稿したいのですが、現在の評判では許可されていません。わかりやすい参考文献や具体的な例に感謝します。関連する問題について明確にさせていただきます。

乾杯!

4

1 に答える 1

4

これには多くの質問が詰め込まれていますが、それらのいくつかに対処しようとします。

非同期 I/O は、特に大量のリクエストを処理するサーバーでは良いことです。より少ないスレッドを使用して、より多くのリクエストを処理できます。あなたが書いているようなプロキシの場合、(外部 URL へのリクエストを行う) HTTP クライアントも非同期にして、リクエストの処理やリモート レスポンスの受信に I/O のブロックが含まれないようにする必要があります。

とは言うものの、基本的に非同期であるNettyのようなフレームワークを使用するよりも、非同期 I/O が追加されている Tomcat や Java EE サーバーで一般的にこのようなことを行うのは難しいかもしれません。Netty の上に構築されたフレームワークの作成者として、私は少し偏見があります。

説明したことを実行するために必要なコードがどれほど少ないかを示すために、ここで説明したことを実行する小さなサーバーを3つのJavaソースファイルで作成し、githubに配置しましたjava -jar-それを試して実行できるスタンドアロンJARを構築します、そして私はそれを明確にコメントしようとしました。

つまり、ネットワーク化されたアプリケーションは、ほとんどの時間を I/O の発生を待つことに費やします。特にプロキシの場合、従来のスレッド化された I/O を使用すると、リクエストを受け取り、リクエストを受け取ったスレッドが同期的に応答する責任があります。そのスレッドは、リモート サーバーからの応答を待ってブロックされます。つまり、スレッドは他の目的には使用できません。したがって、10 個のスレッドがあり、それらすべてが応答を待機している場合、そのうちの 1 つが終了してスレッドを解放するまで、サーバーはそれ以上要求に応答できません。非同期 I/O では、コールバックを取得します一部の I/O が完了したとき。言い換えると、OS がデータをソケットにフラッシュしてネットワーク カードから出力するまでじっとしているのではなく、何かする必要がある場合 (プロキシ リクエストからの応答など) に、コードの肩を優しくタップするだけです。コードがその HTTP リクエストの完了を待っている間、プロキシ リクエストを送信したスレッドは、別のリクエストを処理するために自由に使用できます。つまり、1 つのスレッドが 1 つのリクエストを少し処理し、別のスレッドを少し処理し、別のスレッドを別のリクエストで少し処理することができます。 、そして最終的に最初のリクエストを終了します。スレッドはオペレーティング システムによって提供される有限のリソースであるため、これにより、はるかに少ないハードウェアでより多くのことを実行できます。

Callablevs.に関しては、作業が発生したときに移動DeferredResultするだけです ( は後で実行されますが、何らかのスレッドなどで実行されますが、同期的に結果を返すことが期待されています)。 これにより、コードがオフになり、必要な作業を実行し、設定する必要がある場合はいつでも結果を設定できるため (応答の完了をトリガーする)、必要なもののように聞こえます。CallableCallableDeferredResult

正直なところ、これを本当に効率的に実装したいのであれば、Java EE スタックから離れたほうがよいと思います。上流に泳いでいます (たとえば、JDBC には同期 I/O が組み込まれています。これを本当にスケーリングして SQL データベースを使用したい場合は、このようなものを使用することをお勧めします)。

この種の目的でNettyを使用する別の例については、 tiny-maven-proxyプロジェクトを参照してください。コードはあまりきれいではありませんが、応答本文がクライアントにチャンク単位で供給される HTTP プロキシの実行例を示しています。つまり、大量の応答を伴う要求であっても、プロキシがメモリ不足になることはありません。Tiny-maven-proxy もファイルシステムにキャッシュします。コードがより複雑になるため、デモではこれらのことを行いませんでした。

于 2015-02-07T05:01:43.253 に答える