Tomcat プロセスの CPU 使用率が高い場合の解決策

Tomcat プロセスの CPU 使用率が高い場合の解決策

CPU は多くの場合、システム パフォーマンスのボトルネックになります。次のような原因が考えられます。

  • メモリリークは頻繁なGCにつながり、CPU使用率の上昇につながります。
  • コード バグにより多数のスレッドが作成され、CPU コンテキストの切り替えが頻繁に発生します。

CPU使用率が高すぎると言う場合、比較のためのベンチマーク値を意味します。例えば、

  • ピーク負荷時の JVM の平均 CPU 使用率 40%
  • CPU使用率が80%に達すると異常とみなされます

JVM プロセスは複数の Java スレッドで構成されます。

  • 仕事を待っている人もいる
  • 他の人は使命を帯びている

最も重要なことは、どのスレッドが CPU を消費しているかを調べ、スレッド スタックを通じて問題のあるコードを見つけることです。個々のスレッドの CPU 使用率が特に高くない場合は、スレッド コンテキストの切り替えが CPU 使用率の高さの原因になっているかどうかを検討します。

場合

プログラムは高いCPU使用率をシミュレートします - スレッドプールに4096個のスレッドを作成します

Linux環境でプログラムを起動します。

java -Xss256k -jar デモ-0.0.1-SNAPSHOT.jar

スレッド スタック サイズは 256 KB に指定されています。テスト プログラムの場合、4096 個のスレッドを作成する必要があるため、オペレーティング システムのデフォルト値 8192 KB は大きすぎます。

top コマンドを使用すると、Java プロセスが CPU の 961.6% を使用しており、プロセス ID が 55790 であることがわかります。

より洗練された top コマンドを使用して、この Java プロセス内の各スレッドの CPU 使用率を表示します。

#トップ -H -p 55790 

「scheduling-1」というスレッドがCPUを大量に占有しており、42.5%に達していることがわかります。したがって、次のステップは、このスレッドが何をしているのかを調べることです。

スレッドが何をしているかを調べるには、jstack を使用してスレッド スナップショットを生成します。
jstack の出力は大きく、通常はファイルに書き込まれます。

jstack 55790 > 55790.log

55790.log を開き、手順 4 で見つかったscheduling-1という名前のスレッドを見つけます。そのスレッド スタックは次のとおりです。

AbstractExecutorService#submit の関数呼び出しを見ると、これは Spring Boot によって開始される定期的なタスク スレッドであり、スレッド プールにタスクを送信して CPU を大量に消費していることがわかります。

コンテキスト切り替えのオーバーヘッド?

上記のプロセスを実行すると、CPU を大量に消費するスレッドや、デッド ループなどのバグ コードを見つけることができる場合が多くあります。しかし、このケースでは、Java プロセスが CPU の 961.6% を占有しているのに対し、「scheduling-1」スレッドは CPU の 42.5% しか占有していません。では、残りの CPU は誰が占有しているのでしょうか?

ステップ 4 では、top -H -p pid コマンドで表示されるスレッド リストに「pool-1-thread-x」という名前のスレッドが多数あります。個々の CPU 使用率は高くありませんが、数は比較的多いようです。ご想像のとおり、これらはスレッド プール内で作業を実行するスレッドです。残りの CPU はこれらのスレッドによって消費されますか?

また、主にこれらのスレッド プール内のスレッドが実際に動作しているのか、それとも「休止」しているのかを確認するために、jstack の出力結果を確認する必要もあります。

これらの「pool-1-thread-x」スレッドは基本的に WAITING 状態にあることがわかります。

  • ブロッキングとは、クリティカル セクションでスレッドがロック (Lock または synchronized キーワード) を待機しているためにブロックされている状態を指します。この状態のスレッドはまだロックを取得していないことに注意してください。
  • 待機とは、スレッドがロックを取得したが、他のスレッドが特定の操作を実行するのを待機する必要があることを意味します。たとえば、Object.wait、Thread.join、または LockSupport.park メソッドが呼び出されると、Waiting 状態になります。前提として、スレッドはすでにロックを取得しており、Waiting 状態に入る前に OS レベルで自動的にロックが解放されます。待機条件が満たされると、Object.notify または LockSupport.unpark メソッドが外部から呼び出され、スレッドは再びロックを競い合います。ロックの取得に成功した場合にのみ、Runnable 状態に入り、実行を継続できます。

「pool-1-thread-x」スレッドに戻ると、これらのスレッドは「待機中」状態です。スレッド スタックから、これらのスレッドが getTask メソッド呼び出しを「待機中」であることがわかります。スレッドはスレッド プールのキューからタスクを取得しようとしますが、キューが空であるため、LockSupport.park 呼び出しによって「待機中」状態になります。 「pool-1-thread-x」スレッドはいくつありますか?次のコマンドはスレッドの数をカウントするために使用され、結果は 4096 となり、これはスレッド プール内のスレッドの数とまったく同じです。

grep -o 'pool-2-thread' 55790.log | wc -l

残りの CPU を消費するのは誰ですか?
Java プロセスに多数のスレッドがあるため、CPU コンテキスト切り替えのオーバーヘッドが疑われます。

vmstat コマンドを使用して、オペレーティング システム レベルでのスレッド コンテキスト切り替えアクティビティを表示してみましょう。

cs 列はスレッド コンテキスト スイッチの数を示し、in は CPU 割り込みの数を示します。これら 2 つの数値は非常に高いことがわかりました。これは基本的に、スレッド コンテキスト スイッチが大量の CPU を消費するという私たちの推測を裏付けています。
どのプロセスが原因ですか?

Spring Boot プログラムを停止し、vmstat コマンドを再度実行します。in と cs の両方が大幅に低下していることがわかります。これにより、スレッド コンテキスト切り替えのオーバーヘッドの原因となる Java プロセスが 55790 であることが確認できます。

要約する

CPU 使用率が高すぎる場合は、まず原因となっているプロセスを特定します。次に、top -H -p pid コマンドを使用して特定のスレッドを特定します。
次に、スレッドの数やスレッドの状態を確認するには、jstack を通じてスレッドの状態を確認する必要があります。スレッドの数が多すぎる場合は、スレッドのコンテキスト切り替えのオーバーヘッドが発生している可能性があります。これは、vmstat と pidstat という 2 つのツールで確認できます。

Tomcat プロセスが CPU を過剰に占有する問題を解決する方法についての記事はこれで終わりです。Tomcat プロセスが CPU を過剰に占有する問題の詳細については、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • SpringBootは組み込みTomcat実装手順を開始します
  • Tomcat は親の委任メカニズムを破壊して Web アプリケーションの分離を実現します。
  • Tomcatが親の委任メカニズムを破壊する方法についての簡単な説明
  • Tomcatを使用して共有ライブラリを設定し、同じjarを共有する
  • Tomcat の面接の質問が 15 問も出る、滅多にない機会です!

<<:  シンプルなウェブデザインコンセプトのカラーマッチング

>>:  MySQL query_cache_type パラメータと使用方法の詳細

推薦する

MySQL のデッドロック チェックとデッドロック除去の例の詳細な説明

1. クエリプロセスプロセスリストを表示2. 対応するプロセスを照会し、IDを強制終了します。検証(...

ローカルストレージにブール型の値を保存する際の落とし穴を解決する

LocalStorageはブール値を保存します今日、ブール値データを保存するために localsto...

eject を使用せずに create-react-app の設定を変更する方法

1. イジェクトが推奨されないのはなぜですか? 1. eject を実行した後、どのような変化があり...

MySQLの結合クエリ、ユニオンクエリ、サブクエリの原理と使用例の詳細な説明

この記事では、例を使用して、MySQL の結合クエリ、結合クエリ、サブクエリの原理と使用方法を説明し...

React Router V6 のアップデート

目次ReactRouterV6 の変更1. <Switch> が <Routes&...

一般的なMySQLコマンドの概要

mysqlrootパスワードの設定と変更初めて MySQL データベースに入ります。 !環境変数にm...

Webデザインチュートリアル(2):模倣と盗作について

<br />前回の記事では、Webデザインの手順と方法を紹介しました。詳細については、前...

JavaScript はクラス宝くじアプレットを実装します

この記事では、クラス抽選アプレットを実装するためのJavaScriptの具体的なコードを参考までに紹...

MySQL 正規表現 (regexp と rlike) の検索機能の例分析

この記事では、例を使用して MySQL 正規表現 (regexp および rlike) の検索機能を...

Docker ベースの MySQL マスタースレーブレプリケーション環境を構築するための実装手順

1. はじめに以前のプログラム アーキテクチャは次の形式になります。プログラムのサイズが大きくなると...

MySQL でデータベースを作成した後、ユーザー 'root'@'%' によるデータベース 'xxx' へのアクセスが拒否される問題を解決する

序文最近、仕事で問題が発生しました。データベースを作成した後、データベースに接続するときにエラーが発...

Vue.js ソースコード解析のカスタム手順の詳細な説明

序文コア機能のデフォルトの組み込みディレクティブ (v-model および v-show) に加えて...

border-radius 値の設定に関する質問

問題記録今日はプログレスバーに似た小さなコンポーネントを完成させるつもりでした。プロトタイプは次のよ...

高性能な HTML アプリケーションを作成するためのヒント

Web ページのパフォーマンスを向上させるにはどうすればよいでしょうか?ほとんどの開発者は、Java...

Docker イメージの作成、アップロード、プル、およびデプロイ操作 (Alibaba Cloud を使用)

学習プロセス中にプッシュ イメージが常にタイムアウトすることがわかったため、Alibaba Clou...