高並行性での最適化されたTomcatパフォーマンスの詳細な説明

同時実行性の高い環境では、tomcatの構成を最適化し、接続とスレッドプールの数を変更することを知っています。最も重要なことは、コネクターHttpコネクターのプロトコルがデフォルトのAJPコネクターではなくNIOを使用することです。そのとき、私はその原理を注意深く検討しませんでした。上記の設定を分析してみましょう。

これらを理解するために、tomcatの最も重要な機能の1つはコネクターです。

その役割は、Tomcatのコアであり、Tomcatの構成ファイルserver.xmlで記述されています。コネクタの主な機能は、接続要求を受信し、要求側とデータを交換するための要求オブジェクトと応答オブジェクトを作成してから、エンジン(サーブレット)にスレッドを割り当てます。コンテナ)リクエストを処理し、リクエストエンジンとレスポンスオブジェクトをエンジンエンジンに渡します。エンジンはリクエストを処理した後、コネクタを介してクライアントにレスポンスを返します。

ようやく原理がわかり、リクエストオブジェクトとレスポンスオブジェクトを作成したユーザーがわかりました。

サーブレットコンテナは、コネクタコネクタによってディスパッチおよび制御される必要があると言えます。コネクタコネクタは、Tomcat処理リクエストのバックボーンです。そのため、コネクタの構成と使用は、Tomcatのパフォーマンスに決定的な影響を与えます。話をしましょうコネクタ構成オプション、接続プロトコル、接続数、スレッドプール。

最初に接続プロトコルについて話しましょう。tomcatの接続プロトコルには、主にHTTPコネクターとAJPコネクター(デフォルト)の2つのタイプがあります。

一、BIO、NIO、4月 

1.コネクタのプロトコル

コネクターは、HTTP要求を処理するときにさまざまなプロトコルを使用します。Tomcatのバージョンが異なると、サポートするプロトコルも異なります。最も一般的なプロトコルには、BIO、NIO、およびAPRが含まれます(これら3つのタイプはTomcat7でサポートされ、Tomcat8はNIO2のサポートを追加し、Tomcat8.5およびTomcat9.0は権利を削除しますBIOサポート)。

名前が示すとおり、BIOはブロッキングIOであり、ブロッキングIOです。NIOは非ブロッキングIOであり、非ブロッキングIOです。APRは、ApacheポータブルランタイムライブラリであるApacheポータブルランタイムです。ローカルライブラリを使用すると、高いスケーラビリティとパフォーマンスを実現できます。Aprは、Tomcatで同時実行アプリケーションを実行するための推奨モードですが、apr、apr-utils、tomcatのインストールが必要です-ネイティブおよびその他のパッケージ。(APRは以前に使用されていません。このプロトコルは高い並行性で使用されるようです)

2.プロトコルの指定方法

コネクタが使用するプロトコルは、<connector>要素のprotocol属性で指定するか、デフォルト値を使用できます。

指定されたプロトコル値と対応するプロトコルは次のとおりです。

HTTP / 1.1:デフォルト値、使用されるプロトコルはTomcatのバージョンによって異なります

org.apache.coyote.http11.Http11Protocol:BIO

org.apache.coyote.http11.Http11NioProtocol:NIO

org.apache.coyote.http11.Http11Nio2Protocol:NIO2

org.apache.coyote.http11.Http11AprProtocol:APR

プロトコルが指定されていない場合、HTTP / 1.1のデフォルト値が使用され、意味は次のとおりです。Tomcat7では、BIOまたはAPRの使用を自動的に選択します(APRで必要なローカルライブラリが見つかった場合はAPRを使用し、それ以外の場合はBIOを使用します); Tomcat8では自動的にNIOまたはAPRを使用することを選択します(APRで必要なローカルライブラリが見つかった場合は、APRを使用します。それ以外の場合はNIOを使用します)。

3. BIO / NIOの違いは何ですか

BIOでもNIOでも、要求を処理するコネクターの一般的なフローは同じです。

受け入れキューで接続を受信します(クライアントがサーバーに要求を送信するとき、クライアントとOSが接続を確立するために3ウェイハンドシェイクを完了すると、OSは接続を受け入れキューに入れます)、接続で要求されたデータを取得し、要求を生成します。サーブレットコンテナを呼び出してリクエストを処理し、レスポンスを返します。次の説明を容易にするために、まず、接続と要求の関係を明確にします。接続は、ソケットに対応するTCPレベル(トランスポート層)にあり、要求はHTTPレベル(アプリケーション層)にあり、TCP接続の実装に依存する必要があります。TCP接続複数のHTTPリクエストが送信される場合があります。

BIOによって実装されたコネクターでは、リクエストを処理する主なエンティティはJIoEndpointオブジェクトです。JIoEndpointはAcceptorとWorkerを維持します:Acceptorはソケットを受信し、Workerスレッドプールからアイドルスレッドを見つけてソケットを処理します。Workerスレッドプールにアイドルスレッドがない場合、Acceptorはブロックします。ワーカーは、Tomcatに付属するスレッドプールです。他のスレッドプールが<Executor>を介して構成されている場合、原理はワーカーと同様です。

NIO実装コネクタでは、リクエストを処理するメインエンティティはNIoEndpointオブジェクトです。AcceptorとWorkerに加えて、NIlerEndpointではPollerが使用されています。処理フローを次の図に示します。

Acceptorがソケットを受け取った後、ワーカーのスレッドを直接使用してリクエストを処理する代わりに、リクエストは最初にポーラーに送信され、ポーラーはNIOの鍵となります。Acceptorは、一般的なプロデューサー/コンシューマーモデルを使用して、キューを介してポーラーにリクエストを送信します。ポーラーでは、セレクターオブジェクトが維持されます。ポーラーがキューからソケットを取得すると、セレクターに登録されます。その後、セレクターを反復処理して読み取り可能なソケットを見つけ、ワーカー内のスレッドを使用して対応するリクエストを処理します。BIOと同様に、Workerもカスタムスレッドプールに置き換えることができます。

上記のプロセスからわかるように、NIoEndpointによるリクエストの処理プロセスでは、アクセプターがソケットを受信するか、スレッドがリクエストを処理するかにかかわらず、ブロッキングメソッドが引き続き使用されますが、「ソケットを読み取ってワーカースレッドに渡す」プロセスです。非ブロッキングNIOの実装では、これはNIOモードとBIOモードの最も重要な違いです(他の違いはパフォーマンスへの影響が少ないため、当面は説明しません)。この違いにより、同時実行が大量にある場合に、Tomcatの効率が大幅に向上します。

現在、ほとんどのHTTP要求は長い接続を使用しており(HTTP / 1.1のデフォルトのキープアライブはtrue)、現在の要求が終了した後に新しい要求がない場合、TCPソケットはすぐには解放されません。 、しかし解放する前にタイムアウトを待ちます。BIOを使用する場合、「ソケットを読み取ってワーカースレッドに渡す」プロセスはブロックされます。つまり、ソケットが次のリクエストを待っている間または解放を待っている間、ソケットを処理するワーカースレッドは常に占有されます。これは解放できないため、Tomcatが同時に処理できるソケットの数は最大スレッド数を超えることはできず、パフォーマンスは大幅に制限されます。NIOでは、「ソケットを読み取ってワーカースレッドに渡す」プロセスは非ブロッキングです。ソケットが次のリクエストを待っているとき、または解放を待っているとき、ソケットはワーカースレッドを占有しないため、Tomcatが同時に処理できるソケットの数ははるかに多くなります。スレッドの最大数により、同時パフォーマンスが大幅に向上します。

2、3つのパラメーター:acceptCount、maxConnections、maxThreads

Tomcatがリクエストを処理するプロセスを見てみましょう:受け入れキューで接続を受信します(クライアントがサーバーにリクエストを送信すると、クライアントとOSが接続を確立するために3ウェイハンドシェイクを完了すると、OSは接続を受け入れキューに入れます);要求されたデータを取得し、要求を生成し、サーブレットコンテナを呼び出して要求を処理し、応答を返します。

これに対応して、Connectorのいくつかのパラメータ関数は次のとおりです。

1、acceptCount

受け入れキューの長さ。受け入れキュー内の接続数がacceptCountに達すると、キューがいっぱいになり、すべての着信要求が拒否されます。デフォルト値は100です。

2、maxConnections

Tomcatが常に受信して処理する接続の最大数。Tomcatが受信した接続数がmaxConnectionsに達すると、Acceptorスレッドは受け入れキュー内の接続を読み取らないため、Tomcatが受信した接続数がmaxConnections未満になるまで、受け入れキュー内のスレッドはブロックされます。-1に設定すると、接続数は無制限になります。

デフォルト値は、コネクターが使用するプロトコルに関連しています。NIOのデフォルト値は10000、APR /ネイティブのデフォルト値は8192、BIOのデフォルト値はmaxThreadsです(Executorが構成されている場合、デフォルト値はExecutorのmaxThreadsです)。

Windowsでは、APR /ネイティブのmaxConnections値は、設定された値を下回る最大1024の整数倍に自動的に調整されます。2000に設定されている場合、最大値は実際には1024です。

3、maxThreads

リクエスト処理スレッドの最大数。デフォルト値は200です(Tomcat 7と8の両方)。コネクターがエグゼキューターにバインドされている場合、コネクターは組み込みスレッド・プールの代わりにバインドされたエグゼキューターを使用してタスクを実行するため、この値は無視されます。

maxThreadsは、実行中のCPUの実際の数ではなく、スレッドの最大数を指定します。実際、maxThreadsのサイズは、CPUコアの数よりもはるかに大きくなります。これは、リクエストスレッドの処理時間が非常に短く、データベースがデータを返すのを待つ、ハードディスクがデータを読み書きするのを待つなど、ほとんどの時間がブロックされる可能性があるためです。したがって、ある時点では、実際には物理CPUを使用しているスレッドはわずかであり、ほとんどのスレッドが待機しているため、スレッドの数が物理コアの数よりはるかに多いのは妥当です。

つまり、TomcatはCPUコアの数よりもはるかに多くのスレッドを使用してCPUをビジー状態にすることができ、CPU使用率を大幅に向上させます。

4.パラメータ設定

(1)maxThreadsの設定は、アプリケーションの特性とサーバーのCPUコアの数の両方に関連しています。以前の概要から、maxThreadsの数はCPUコアの数よりもはるかに大きくする必要があることがわかります。また、CPUコアの数が多いほど、maxThreadsが大きくなります。CPUをフルに活用するには、アプリケーションでのCPU集約型(IO集約型)が少ないほど、maxThreadsが大きくなります。もちろん、maxThreadsの値はそれほど大きくありません。maxThreadsが大きすぎると、CPUはスレッドの切り替えに多くの時間を費やし、全体的な効率が低下します。

(2)maxConnectionsの設定は、Tomcatの動作モードに関連しています。tomcatがBIOを使用している場合、maxConnectionsの値はmaxThreadsと同じである必要があります。tomcatがNIOを使用している場合、Tomcatのデフォルト値と同様に、maxConnectionsの値はmaxThreadsよりはるかに大きい必要があります。

(3)前の紹介から、tomcatが同時に処理できる接続の数はmaxConnectionsですが、サーバーで同時に受信できる接続の数はmaxConnections + acceptCountであることがわかります。acceptCount設定は、接続が高すぎる場合にアプリケーションが実行したいことに関連しています。設定が大きすぎると、着信要求の待機時間が非常に長くなり、設定が小さすぎると、着信要求はすぐに接続拒否を返します。

3、スレッドプールエグゼキュータ

Executor要素はTomcatのスレッドプールを表し、他のコンポーネントと共有できます。このスレッドプールを使用するには、コンポーネントがexecutor属性を使用してスレッドプールを指定する必要があります。

Executorは、Service要素の埋め込み要素です。一般に、スレッドプールを使用するのはコネクタコンポーネントです。コネクタでスレッドプールを使用するには、Executor要素をコネクタの前に配置する必要があります。エグゼキューターとコネクターの構成例は次のとおりです。

<Executor name = "tomcatThreadPool" namePrefix = "catalina-exec-" maxThreads = "150" minSpareThreads = "4" />

<Connector executor = "tomcatThreadPool" port = "8080" protocol = "HTTP / 1.1" connectionTimeout = "20000" redirectPort = "8443" acceptCount = "1000" />

エグゼキューターの主な属性は次のとおりです。

名前:スレッドプールのタグ

maxThreads:スレッドプール内のアクティブなスレッドの最大数、デフォルト値は200(Tomcat 7と8の両方)

minSpareThreads:スレッドプールに保持されるスレッドの最小数。最小値は25です。

maxIdleTime:スレッドがアイドル状態である最大時間。アイドル値がこの値を超えたときにスレッドを閉じます(スレッド数がminSpareThreads未満の場合を除く)。単位はmsで、デフォルト値は60000(1分)です。

デーモン:バックグラウンドスレッドであるかどうかにかかわらず、デフォルト値はtrueです。

threadPriority:スレッドの優先度、デフォルト値5

namePrefix:スレッド名のプレフィックス。スレッドプール内のスレッド名は、namePrefix +スレッド番号です。

4番目に、現在のステータスを表示します

Tomcat接続数とスレッド数の概念とそれらの設定方法については上記で説明しましたが、次に、サーバー内の接続数とスレッド数を表示する方法について説明します。

サーバーのステータスの表示は、2つのオプションに大きく分けられます。(1)既製のツールを使用する、(2)Linuxコマンドを使用して直接表示する。

JDKに付属するjconsoleツールなどの既製のツールを使用すると、スレッド情報(さらに、CPU、メモリ、クラス、JVMの基本情報なども表示できます)、Tomcat独自のマネージャー、および課金ツールNew Relicを簡単に表示できます。次の図は、スレッド情報を表示するためのjconsoleのインターフェースです。

Linuxコマンドラインを使用してサーバーの接続数とスレッド数を確認する方法について説明します。

1.接続数

Tomcatがhttpリクエストを受信するためのポートが8083であるとすると、次のステートメントを使用して接続を表示できます。

netstat-夜| グリップ8083

結果は次のとおりです。

 

リッスン状態でリクエストをリスニングしている接続があり、さらに、4つの確立された接続(ESTABLISHED)と2つの接続が閉じられるのを待っている(CLOSE_WAIT)ことがわかります。

2.スレッド

psコマンドは、次のコマンドの実行など、プロセスのステータスを表示できます。

結果は次のとおりです。

 

プロセス情報が1つだけ出力されていることがわかります。27989はスレッドIDで、javaは実行されたjavaコマンドを指します。これは、Tomcatを開始すると、メインスレッド、ガベージコレクションスレッド、アクセプタースレッド、要求処理スレッドなど、すべての内部作業がこのプロセスで完了するためです。

次のコマンドを使用すると、プロセスに存在するスレッドの数を確認できます。nlwpは、軽量プロセスの数を意味します。

ps –o nlwp 27989

 

プロセスには73のスレッドがあることがわかりますが、73はアイドル状態のスレッドを除外しません。実行中のスレッドの実際の数を取得するには、次のステートメントを使用できます。

ps -eLo pid、state | グリップ27989 | 実行中のgrep | トイレ-l

その中で、ps -eLo pidとstatはすべてのスレッドを検出し、プロセス番号とスレッドの現在の状態を出力できます; 2つのgrepコマンドはプロセス番号とスレッドステータスをフィルタリングし、wcは番号をカウントします。このうち、ps -eLo pid、stat | grep 27989の出力結果は次のとおりです。

 

結果の一部のみがスクリーンショットです。Slは、ほとんどのスレッドがアイドル状態であることを示しています。

おすすめ

転載: www.linuxidc.com/Linux/2020-04/162923.htm