この記事を通して、主に、Java開発とソリューションでサーブレット3.0非同期処理で発生した問題を説明します。以下は特定の内容です。
サーブレット3.0は、リクエストの非同期処理をサポートするためにAsynccontextを提供し始めました。では、リクエストの非同期処理にはどのような利点がありますか?
一般的に、Webコンテナがリクエストを処理する方法は、各リクエストにスレッドを割り当てることです。私たちは皆、スレッドの作成にはコストがないわけではなく、Webコンテナのスレッドプールには上限があります。
非常に予測可能な問題は、高負荷条件下ではスレッドプールが占有されているため、その後のリクエストは待機することしかできないことです。運が良くない場合、クライアントは待機中のタイムアウトエラーを報告します。
Asynccontextが表示される前に、この問題を解決する唯一の方法は、Webコンテナのスレッドプールを拡張することでした。
しかし、これにはまだ問題があります。次のシナリオを考慮してください。
スレッドプールサイズが200のWebコンテナがあります。2つのサーブレットを備えたWebアプリがあります。単一のリクエストを処理するのにサーブレットAが10秒で、Servlet-Bが1つのリクエストを処理するのにかかる時間は1秒です。
これで、サーブレットAへの200を超えるリクエストがある高負荷に遭遇します。この時点でサーブレット-Bが要求された場合、すべてのHTTPスレッドがサーブレットAによって占有されているため、待ちます。
この時点で、エンジニアは問題を発見し、スレッドプールのサイズを400に拡大しましたが、負荷は増加し続けました。現在、サーブレットAへの400のリクエストがあり、サーブレット-Bはまだ応答できません。
問題を見たことがありますか? HTTPスレッドとワーカースレッドは結合されているため、時間のかかる操作に多数のリクエストが行われると、HTTPスレッドが埋められ、Webコンテナ全体が応答できません。
ただし、AsynCcontextを使用すると、時間のかかる操作を別のスレッドに引き渡すことができ、HTTPスレッドがリリースされ、他のリクエストを処理できます。
Asynccontextのみを使用すると、上記の効果が得られることに注意してください。新しいスレッド()または同様の方法を直接使用する場合、HTTPスレッドはコンテナに返されません。
公式の例は次のとおりです。
@webservlet(urlpatterns = {"/asyncservlet"}、asyncsupported = true)public class asyncservletはhttpservletを拡張します{/ * ...同じ変数とsyncservlet ... */@override public void doget Response.setContentType( "text/html; charset = utf-8"); final asynccontext acontext = request.startasync(); acontext.start(new runnable(){public void run(){string param = acontext.getRequest()。getParameter( "param"); string result = resource.process(param); httpservletResponse response = acontext.getResponse(); / * ...応答への印刷... }}トラップ
この公式の例では、各HTTPスレッドが別のワーカースレッドを開いてリクエストを処理し、HTTPスレッドをWebコンテナに返します。ただし、asynccontext.start()メソッドのjavadocを見てください。
コンテナは、おそらく管理されたスレッドプールからスレッドを派遣して、指定されたrunnableを実行します。
実際、ここには、労働者のスレッドが登場する規制はありません。多分それはHTTPスレッドプール以外の別のスレッドプールでしょうか?それとも、それは単なるHTTPスレッドプールですか?
asynccontext.start()の記事の限られた有用性は読み取ります:さまざまなWebコンテナには異なる実装がありますが、Tomcatは実際にHTTPスレッドプールを使用してAsynccontext.start()を処理します。
これは、もともとHTTPスレッドをリリースしたいと考えていたことを意味しますが、実際にはhttpスレッドがワーカースレッドとして使用されているためではありませんでしたが、このスレッドはリクエストを受信するHTTPスレッドと同じではありません。
また、AsyncServlet1とSyncServletのJMeterベンチマークを通じてこの結論を見ることができ、2つのスループットの結果は類似しています。メソッドの開始:メインを開始し、jmeterを使用してbenchmark.jmx(httpスレッドプール= 200のデフォルト構成の下で200)を開始します。
ExecutorServiceを使用します
Tomcatがワーカースレッドプールを個別に維持していないことを以前に見たので、自分でそれを行う方法を見つけなければなりません。AsyncServlet2を参照してください。
他の方法
したがって、asynccontextを使用する固定方法はありません。さまざまな方法を使用して、実際のニーズに応じて対処できます。このため、Java Concurrentプログラミングの知識が必要です。
パフォーマンスの誤解
Asynccontextの目的は、パフォーマンスを改善することではなく、パフォーマンスの向上を直接提供することでもありません。 HTTPスレッドとワーカースレッドを分離するメカニズムを提供し、それによりWebコンテナの応答性を改善します。
ただし、Asynccontextはある時点でパフォーマンスを改善できますが、これはコードの書き込み方法に依存します。
たとえば、Webコンテナ内のHTTPスレッドプールの数は200で、サーブレットは300ワーカースレッドプールを使用してAsynccontextを処理します。
同期メソッドワーカースレッドプール= HTTPスレッドプール= 200と比較して、この場合は300のワーカースレッドプールがあるため、間違いなくパフォーマンスの改善がもたらされます(結局、より多くの人が働いています)。
それどころか、ワーカースレッドの数が<= HTTPスレッドの数である場合、処理リクエストのボトルネックはワーカースレッドにあるため、パフォーマンスの改善はありません。
AsyncServlet2のスレッドプールサイズを変更し、SyncServletベンチマークの結果と比較して、この結論を検証できます。
ワーカースレッドプールはHTTPスレッドプールよりも大きくなければならないとは思わないでください。理由は次のとおりです。
2つの責任は異なります。 1つは、Webコンテナが外部リクエストを受信するために使用され、もう1つはビジネスロジックを処理することです。
スレッドの作成には費用がかかります。 HTTPスレッドプールがすでに大きい場合、より大きなワーカースレッドプールを作成すると、コンテキストスイッチとメモリオーバーヘッドが多すぎます。
Asynccontextの目的は、HTTPスレッドをリリースして、操作の長期使用を回避し、Webコンテナが応答できないようにすることです。
したがって、ほとんどの場合、ワーカースレッドプールはそれほど大きくなく、さまざまなビジネスに従って異なるワーカースレッドプールが構築されます。
たとえば、Webコンテナスレッドプールサイズは200で、ワーカースレッドプールサイズは遅いサーブレットの場合は10です。このようにして、操作を遅くするためにいくつのリクエストを使用しても、HTTPスレッドを埋めず、他のリクエストが処理できなくなります。