問題を切り分けるためには、情報を取得しないといけません。実行中のJavaアプリケーションから情報を取得する方法はたくさんありますが、よく使われている方法として、ログ出力、JMXとMBean、ダンプの3つを紹介します。
情報を取得する方法として、ほかにも以下のようなものが存在します。
- Javaの仕様に則った方法(JVMTI:Java Virtual Machine Tool Interfaceを使ってJava VMへ接続する、など)
- JVMやAPサーバの実装に固有の機能を使う方法
しかし、一般的に使われる方法ではなかったり、必要最低限の情報を取得するには負荷が高すぎて実運用に耐えられなかったり、使用するミドルウェアに依存する機能であるため、本連載では取り扱いません。
ログを出力する
「どのような状況で、どのような処理を行ったか」をログとして出力することは、Javaに限らず、情報を取得する最も一般的な方法でしょう。ログは、アプリケーション、アプリケーションサーバ、Java VMごとにそれぞれが出力します。
一般的に、ログはレベルがあります。レベルがあることによって、出力したいログとしたくないログ、詳細に出力したいログなどを制御できます。レベルの定義はさまざまありますが、アプリケーションの場合は以下のレベルに分けることが多いです。
アプリケーション、APサーバ、Java VMのそれぞれの開発者は、どのレベルで、どのログを出力するかを考えながら開発します。実行時にすべてのログを出力すると膨大な量となるためです。
- アプリケーション
アプリケーション開発者が出力したい情報を、ログとして出力します。標準出力や標準エラー出力へログを出力することはなく、ログを出力するライブラリか、Javaに含まれるロギングAPIをアプリケーション開発者が使用して、それらに含まれるログレベルごとに用意されたAPIを使用してログを出力します。
- APサーバ
「処理の受付と終了のログ」や「外部接続の開始と終了のログ」などを出力しますが、どのようなログを出力できるかはAPサーバごとに異なります。どのログを、どのレベルで出力するかは、APサーバの設定ファイルや設定画面で設定します。アプリケーションがアプリケーションサーバのログ機構を使用する場合にも、同様に設定します。
- JVM
ガベージコレクション(GC)やクラスのロードなど、アプリケーションを動かすためにどのような処理をしたかを出力します。ログを出力するには、JVMの起動オプションを追加してJavaプロセスを起動します。たとえば、起動オプションとして-verbose:gcを追加すると、GCログを有効化します。一部の設定は、この後の紹介するJMXを使用しても設定できます。
JMXとMBean
「処理を受け付けた件数」や「用意しているリソースの使用量」などは、一般的にJavaアプリケーションは外部から監視ツールで一元管理されます。そのような場合には、Java Management Extensions(JMX)とManaged Bean(MBean)を使用します。
以下の手順で、JMXとMBeanで情報を取得します。
- JMXを使用してJavaプロセスへアクセスできるように設定する
- JMXクライアントを使用して、MBeanサーバへ接続する
- MBeanの名前を指定することで、MBeanへアクセスする
MBeanは、情報の取得だけではなく、実装次第でログレベルを変更するなどの操作もできます。JMXクライアントはたくさんの製品やOSS があります。一般的に運用担当者はGUIのJMXクライアントを使用して常時監視するのではなく、10秒間隔など定期的にMBeanへアクセスして情報を取得して、CSVファイルやRDBMS などへ蓄積して異常があれば対処します。以下の例では GUI の JMX クライアントである JConsole を使用します。
1. JMXを使用して、Javaプロセスへアクセスできるように設定する
同一のOSの上で動いているJavaプロセス(ローカルJavaプロセス)へアクセスするには特に何もする必要はありませんが、リモートの場合は、JMXのリモート接続を有効化します。リモート接続の有効化は、JVMの起動オプションに以下を追加します。
ポート番号や認証の有無、暗号化の有無も、別途設定できます。
2. JMXクライアントを使用して、MBeanサーバへ接続する
JMXクライアントであるJConsoleを起動すると、ダイアログの上側にローカルJavaプロセスの一覧、下側にリモートプロセスのURLを入力する項目があります、ローカルJavaプロセスへ接続するには一覧の中から接続したいプロセスを選択します。
リモートプロセスへ接続する場合は、IPアドレスとポート番号を指定して接続します。必要に応じてユーザ名、パスワードも指定します。
3. MBeanの名前を指定してMBeanへアクセスする
接続後、概要タブが選択されているので、MBeansタブを選択します。
ここでは、ランタイムの情報を管理するMBeanであるjava.lang:type=Runtimeへアクセスする例を挙げます。
まず、左側のツリーあるjava.lang というディレクトリを選択します。
次に、Runtimeを選択します。
属性以下にある項目を選択することで、このMBeanが公開している情報を確認できます。
実装によりますが、一般的にJVMやAPサーバはたくさんのMBeanを公開しています。以下は一例です。
- アプリケーションサーバ → サーブレットへのアクセス数、データソースの使用数など
- JVM → ランタイム、ヒープの情報
ダンプする
トラブルシュートや動作確認のため、スレッドやヒープのリソースがどのように使われているかを詳細に確認したいときがあります。そのような場合には、Java VMが持つリソースをそのまま出力することで情報を取得します。
リソースを出力することをダンプと呼び、それによって作成されるファイルをダンプファイルと呼びます。ダンプファイルには、出力を行った瞬間の情報が含まれています。
注意していただきたいのは、ダンプには非常に多くのリソースと時間を消費することです。そのため、ダンプの取得は、リソースを消費してよく、時間がかかってもいい時間に行いましょう。また、ヒープダンプは、ダンプファイルがヒープサイズを超えるサイズになることもあるので、ダンプ先となるストレージには十分な空き容量が必要です。
ダンプファイルには情報が膨大にあるため、JVisualVMなどのツールを使用することをおすすめします。これらツールには、1つのダンプファイルだけを確認するだけではなく、複数のダンプファイルを同時に開いて差分を確認しやすくする機能が実装されています。これらの機能を使用して分析するようにしましょう。
おわりに
いかがでしたでしょうか? Javaには情報を取得する方法がさまざまあります。公開されている情報を常に監視し、普段と異なる動きになったらログから何が起こったかを確認することで、多くの問題に備えることができるようになります。さらに詳細な情報が必要になった場合は、ダンプファイルを確認して、問題箇所を特定していきます。
次回以降はJVM、APサーバ、アプリケーションでどのような情報を取得するかを紹介していきます。