はじめに
現在のWebシステム開発・運用で踏まえるべき新しい技術的な取り組みについて、日立Cosminexusの製品群を題材として取り上げながら解説する本連載の前回では、トラブルシューティングの前編を解説しました。
第4回の今回は、後編として、Webシステム運用時の主なトラブルを症状別に取り上げながら、トラブルシューティングの流れを説明します。
プロセスハングアップの調査
プロセスハングアップの原因特定に有効な資料としては、PRFトレース(障害解析/性能解析トレース)、スレッドダンプ、OSの統計情報が挙げられます(図1)。まず該当プロセスのCPU使用率を調べます。100%に近い場合は、無限ループまたは再帰呼び出しに陥っている可能性が高いと見られます。逆に0%に近い場合は、DB(データベース)などのバックプロセスから応答が返ってきていないか、スレッド同士でロックを掛け合うデッドロックの可能性が疑われます。トラブルの原因としてはデッドロックよりも、バックプロセスからの応答がない場合が多く見られます。
CPU使用率を調べたあとは、PRFトレースで問題の個所を探し、詳細をJavaVM上の全スレッドの状態およびスタックトレースを出力するスレッドダンプで特定します。
PRFトレースによる解析
PRFトレースは、ブラウザ操作からアプリケーションサーバ、DBに至るまでのトレースを突き合わせ、ミドルウェアの中の動作を可視化できるCosminexus独自の機能です。トレース出力処理と非同期で動作するためシステムの負荷が小さく、本番環境でも利用できるのが特長です。
PRFトレースでは、リクエストごとにユニークなIDを付与してサーバ内の各処理ポイントでトレースを取得します。さらに、DBのコネクションIDとのマッチングによりWebサーバからDBまでの処理シーケンスを容易に把握できます(図2)。出力形式はCSV(Comma Separated Values;カンマ区切り)のため、Excelなど一般的な表計算ソフトで見ることができます。
プロセスハングアップ発生時にPRFトレースの出力を解析すると、リクエストID、日付、時刻(ナノ秒単位)から特定のプロセスで異常に処理時間が長い個所が見つかります。これにより、どの処理でプロセスハングアップが発生しているのかがわかります。
スレッドダンプの解析
プロセスハングアップの発生個所がある程度絞り込めたら、続いてスレッドダンプを解析します。スレッドダンプは2~3秒おきに10回程度実行すると、より正確な解析が可能になります。
複数回取得したスレッドダンプから、tid(スレッドID)が同じスレッドのスタックトレースを比較調査します。
ハングアップ個所がネイティブメソッドの場合は、さらにメモリダンプを解析します。その結果、ハングアップしたモジュールがわかりますので、当該モジュールの開発元に調査を依頼します。
- バックプロセス無応答の場合
複数のスレッドダンプで同一tidのスレッド属性が実行可能状態を表す“runnable”である場合、長時間にわたって同じ処理を実行中となってないかを調べます。
- デッドロックの場合
スレッド属性がロック取得待ちを表す“waiting formonitor entry”のスレッドにおいて、ロックを取得待ちのハッシュコードとロックを取得済みのハッシュコードがお互いにロックを掛け合っているスレッドがないかを調べます。
- 無限ループの場合
複数のスレッドダンプで同一tidのスレッドがすべてrunnableで、同一メソッド内の特定の行が複数回、繰り返し実行している場合は、無限ループが疑われます。
プロセススローダウンの調査
スローダウンとハングアップの現象はよく似ており、スローダウンが長時間になれば、ハングアップと同じ状態と言えます。
そのため、スローダウンの調査方法は、ハングアップと同じ手順で進めます。PRFトレースとスレッドダンプ、必要であればメモリダンプを取得して解析することで、原因モジュールを特定できます。
タイムアウトの調査
タイムアウトの原因特定に有効な資料としてはメッセージログとPRFトレースです。原因調査は、エラーメッセージを確認し、PRFトレースで詳細を特定します。
タイムアウト発生時にはエラーメッセージが表示されますので、ユーザからのエラー報告があった時刻とメッセージログを対比させ、エラーメッセージが出力されていないかを確認します。エラーメッセージを発見できたら詳細を確認し、必要に応じてPRFトレースを解析します。
タイムアウトの種類
タイムアウトの発生個所はシステムの構成により異なりますが、WebサーバとJ2EEサーバがそれぞれ1つずつであるWeb-EJB単一構成の場合は主に2ヵ所に絞られます。
1つめは、WebサーバのリダイレクタとJ2EEサーバ内のWebコンテナとの間で発生するリダイレクタタイムアウトです。2つめは、J2EEサーバ内のEJBコンテナからDBコンテナを経由してDBサーバに至る経路で発生するトランザクションタイムアウトです。
どちらのタイムアウトが発生しているかは、エラーメッセージにより見分けます。
シーケンス図(図3)で見ると、リダイレクタタイムアウトはシステムの入口に近い部分で発生し、トランザクションタイムアウトは奥の部分で発生します。
タイムアウトの調査方法
リダイレクタタイムアウトの場合は、まずPRFトレースで長時間を要している処理を探します。Webコンテナ内部かEJBコンテナ内部であれば、それぞれの開発元に問い合わせます。Webアプリケーションの場合はリクエストURLとサーブレットのクラス名をもとにPRFトレースから該当個所を絞り込み、スレッドダンプを解析して時間を要する処理を特定します。モジュールを特定できたら、開発元に調査を依頼します。
トランザクションタイムアウトの場合も、PRFトレースで時間を要する処理を探します。SQLの実行であればSQL文を見直したり、DBサーバの障害の有無を調べ、DB開発元に調査を依頼します。コネクション取得またはクローズ処理に問題がある場合は、DBコネクタの開発元に調査を依頼します。EJBアプリケーションの場合は、エラーメッセージとPRFトレースか、スレッドダンプから詳細に解析し、問題モジュールの開発元に問い合わせます。
OutOfMemory障害の調査
OutOfMemory障害が発生すると、ログにOutOfMemoryErrorが出力されます。ログに詳細が記述されているので、これらを参照して症状を切り分けます(図4)。
続いて、メモリ量の変化を調査します。症状として、Cヒープ不足またはスレッドが生成できない場合は、OSの統計情報を使い、Javaヒープまたはパーマネントヒープ不足の場合は、Java VMログの情報を使います。
Javaヒープまたはパーマネントヒープ不足でメモリリークが発生している場合は、プロファイル情報を出力するCosminexusの「jheapprof」コマンドを実行し、詳細調査して原因を追及します。「jheapprof」コマンドは、本番環境で実行できるため、障害再現の手間なく調査をすることができます。症状がCヒープ不足またはスレッドが生成できない場合でメモリリークが発生しているなら、発生個所に応じてユーザまたは開発元に見直しを依頼します。メモリ量の変化を観察した結果メモリリークでない場合は、設定を変更して対処します(表1)。Webサーバなどでの同時実行ユーザ数の制限やOSのシステムメモリの拡張、設定の変更などで、OutOfMemory障害を回避することもできます。
表1 症状と対処
症状 | システムの状況 | 対処 |
Java Heap不足 | - Full GC直前のJava Heap量がJava Heapの最大値に到達
- Full GC後もOld領域に空きがない
| - Webサーバなどで同時実行ユーザ数を制限する
- Java Heapの最大値を大きくする
|
Permanent Heap不足 | - Full GC後もPermanent Heapに空きがない
- Full GCが頻発
|
- Permanent Heapの最大値を大きくする
C Heap不足 | - C Heap量が使用可能なメモリ量に到達
- C Heap量がカーネルパラメタの上限値に達した
|
- OSシステムメモリを大きくする
- 不要なプロセスを停止する
- システム上限値を大きくする
- Webサーバなどで同時実行ユーザ数を制限する
スレッドが生成できない | | - システム上限値を大きくする
- Webサーバなどで同時実行ユーザ数を制限する
|
- 生成されたスレッド数が多く、スレッドスタックで使用できるメモリ量が少ない
|
- OSシステムメモリを大きくする
- Webサーバなどで同時実行ユーザ数を制限する
- スレッドスタックサイズを小さくする
|
| |
次回予告
次回はトラブルシューティングの実践編として、実際の事例に基づいてトラブルの解決方法を解説します。