第13章 スレッドプールの設定の概念
このセクションは、Red Hat build of Keycloak 用にスレッドプール接続プールを設定する方法に関する考慮事項とベストプラクティスを説明することを目的としています。これが適用される設定については、Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ を参照してください。
13.1. 概念
13.1.1. Quarkus エグゼキュータープール
Red Hat build of Keycloak のリクエストとブロッキングプローブは、エグゼキュータープールによって処理されます。利用可能な CPU コア数に応じて、プールのサイズは最大 200 スレッド以上になります。スレッドは必要に応じて作成され、不要になると終了するため、システムは自動的にスケールアップおよびスケールダウンします。Red Hat build of Keycloak では、http-pool-max-threads
設定オプションによって最大スレッドプールサイズを設定できます。例については、Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ を参照してください。
Kubernetes で実行する場合は、Pod に許可された CPU 制限を超える負荷が発生しないようにワーカースレッドの数を調整して、輻輳を引き起こすスロットリングを回避します。物理マシンで実行する場合は、ノードが処理できる以上の負荷が発生しないようにワーカースレッドの数を調整して、輻輳を回避します。輻輳が発生すると、応答時間が長くなり、メモリー使用量が増加し、最終的にはシステムが不安定になります。
可能であれば、下限のスレッド数から始めて、目標のスループットと応答時間に応じて数を調整してください。負荷とスレッド数が増加すると、データベース接続もボトルネックになる可能性があります。リクエストが 5 秒以内にデータベース接続を取得できないと、そのリクエストは失敗し、Unable to acquire JDBC Connection
のようなメッセージがログに記録されます。呼び出し元は、サーバー側のエラーを示す 5xx HTTP ステータスコードを含む応答を受け取ります。
データベース接続数とスレッド数を増やしすぎると、高負荷時にリクエストがキューに蓄積されてシステムが輻輳し、パフォーマンスが低下します。データベース接続の数は、それぞれ Database
設定の db-pool-initial-size
、db-pool-min-size
、および db-pool-max-size
によって設定されます。数値が低いと、負荷が急増したときにリクエストが失敗することがありますが、すべてのクライアントの応答時間が速くなります。
13.1.2. JGroups 接続プール
org.jgroups.util.ThreadPool: thread pool is full
エラーを避けるために、クラスター内のすべての Red Hat build of Keycloak ノードのエグゼキュータースレッドの合計数が、JGroups スレッドプールで使用可能なスレッドの数を超えないようにしてください。初めてエラーが発生したときにエラーを確認するには、システムプロパティー jgroups.thread_dumps_threshold
を 1
に設定する必要があります。そうしないと、10000 件のリクエストが拒否されるまで、メッセージが表示されません。
JGroup スレッドの数はデフォルトで 200
です。これは、Java システムプロパティー jgroups.thread_pool.max_threads
を使用して設定できますが、この値を維持することを推奨します。実験によると、JGroups の通信のデッドロックを回避するには、クラスター内の Quarkus ワーカースレッドの合計数が、各ノードの JGroup スレッドプール内のスレッド数 (200) 以下である必要があります。4 つの Pod を持つ Red Hat build of Keycloak クラスターの場合、各 Pod の Quarkus ワーカースレッド数が 50 個である必要があります。Quarkus ワーカースレッドの最大数は、Red Hat build of Keycloak 設定オプション http-pool-max-threads
を使用して設定します。
メトリクスを使用して、プール内の JGroup スレッドの合計数とプール内でアクティブなスレッドを監視します。JGroups トランスポートプロトコルとして TCP を使用する場合、メトリクス vendor_jgroups_tcp_get_thread_pool_size
および vendor_jgroups_tcp_get_thread_pool_size_active
を監視に使用できます。UDP を使用する場合、メトリクス vendor_jgroups_udp_get_thread_pool_size
と vendor_jgroups_udp_get_thread_pool_size_active
を使用できます。これは、Quarkus スレッドプールサイズの制限により、アクティブな JGroup スレッドの数が JGroup スレッドプールの最大サイズ内に収まっていることを確認するのに役立ちます。
13.1.3. 負荷制限
デフォルトでは、Red Hat build of Keycloak は、リクエストの処理が停止した場合でも、すべての受信リクエストを無限にキューに入れます。これにより、Pod でさらにメモリーが使用され、ロードバランサーのリソースが枯渇する可能性があります。最終的には、リクエストが処理されたかどうかをクライアントが認識することなく、リクエストがクライアント側でタイムアウトになります。Red Hat build of Keycloak でキューに入れられるリクエストの数を制限するには、追加の Quarkus 設定オプションを設定します。
http-max-queued-requests
を設定して最大キュー長を指定し、このキューサイズを超えた場合に効果的な負荷制限を適用できるようにします。Red Hat build of Keycloak Pod が 1 秒あたり約 200 のリクエストを処理すると仮定すると、キューが 1000 の場合、最大待機時間は約 5 秒になります。
この設定がアクティブな場合、キューに入れられたリクエストの数を超えるリクエストに対して、HTTP 503 エラーが返されます。Red Hat build of Keycloak は、エラーメッセージをログに記録します。
13.1.4. プローブ
Red Hat build of Keycloak の liveness プローブは、高負荷時の Pod の再起動を回避するために、ノンブロッキングです。
全体的なヘルスプローブと readiness プローブは、場合によってはデータベースへの接続を確認するためにブロックすることがあるため、高負荷時に失敗する可能性があります。このため、高負荷時には Pod が準備完了状態にならない可能性があります。
13.1.5. OS リソース
Linux 上で Java を実行する場合、Java がスレッドを作成するには、使用可能なファイルハンドルが必要です。したがって、オープンファイルの数 (Linux で ulimit -n
で取得される数) に余裕を確保し、Red Hat build of Keycloak が必要なスレッドの数を増やせるようにする必要があります。各スレッドはメモリーも消費するため、コンテナーのメモリー制限を、これを許容する値に設定する必要があります。そうしないと、Pod が Kubernetes によって強制終了されます。