JAPANESE | ENGLISH |
Jawprof(Java Application Workload Profiling Framework)はJavaアプリケーションのワークロードプロファイリングを行うためのフレームワークです。ワークロード(workload)とは、システムに加わるユーザからの負荷の総称です。システム性能評価の第一歩は、このワークロードを定量的に知ることです。Jawprofはこのワークロードを簡単に測定するための手段を提供することを目的としています。[2]。ワークロードプロファイルには以下の情報が含まれます。
Javaアプリケーション用の負荷検証用のツールとしてJakarta JMeterがあります。このようなソフトウェアはアプリケーションがパフォーマンス要件を満たしているかを検証するために使うことができます。また、パフォーマンス上のホットスポットとなっている部分を探すためのプロファイリングツールも多くのプロダクトがフリーソフトウェアも含めあります。
一方、アプリケーション開発プロジェクトでは要件定義の一部としてパフォーマンス要件を定義することとなります。このパフォーマンス要件の定義は、当然パフォーマンスの基準を定量化することになるわけですが、満たされるべきパフォーマンス要件をアプリケーションの開発の前に決定すること(決断してもらうこと)は困難である場合がほとんどです。そこで、アプリケーション稼動後に実際の運用状況を確認した後、パフォーマンス要件を定義し、その目標までチューニングを行うこともあります。
このパフォーマンス要件の定義を行う根拠となるデータを収集するために、時間帯ごとのCPUやディスクの負荷状況を調べることは可能ですが、アプリケーションのレベルでの情報、例えばのべ何人がアクセスし、商品の検索を実施したのが何人で、購入手続きを行ったのが何人かなど、はアプリケーションレベルで収集するしかありません(2)。
また、稼動後もアプリケーションの視点でどの程度アクセスがあるか、どの時間帯に処理が集中するか、どの処理が多く使用されるのか、何曜日に処理が集中するかなどの情報を元にシステムの保守や改良点の検討が可能になります。
Jawprofは次の目的をサポートします。
モニタリングを開始するときは、モニタIDを指定する必要があります。モニタIDは同時に利用されているモニタを区別するためのものです。セッションオブジェクトを利用することが可能です。
トランザクションにはIDが付与されます。これはJawprof側で付加するもので、呼び出し側が意識する必要はありません。
Jawprofに似ているフレームワークとしてJAMon[1]があります。Jawprofは多くのアイディアをJAMonから得ています。Jawprofに関心のあるプログラマはJAMonも調査するべきです。
JawprofとJAMonには以下の違いがあります(3)。
最後にありますが、Jawprofは集計したりする機能は一切持ち合わせていません。この作業は外部の表計算ソフトや分析ソフトに委ねられる事を想定しています。
JawprofとJawprofが利用しているパッケージとの関係を図2.1.1[Jawprof と関係パッケージ]に示します。
Jawprofはこれらのパッケージに依存しています。従って、これらのパッケージを全てインストールする必要があります。以下に必要なパッケージをまとめます。まだ、これらのパッケージを持っていなければ、ダウンロードするなどして、取得してください。
パッケージ名 | URL | 必須 |
---|---|---|
Jakarta Commons Logging | http://jakarta.apache.org/commons/logging/ | ○ |
Log4J | http://logging.apache.org/log4j/docs/ | |
Jakarta Commons Collections | http://jakarta.apache.org/commons/collections/ | ○ |
Jakarta Commons Pool | http://jakarta.apache.org/commons/pool/ | ○ |
Jakarta Commons DBCP | http://jakarta.apache.org/commons/dbcp/ |
JawprofはアプリケーションからJawprofのAPIを呼ぶことによって利用します。従って、開発しているアプリケーションのコンパイル時にクラスパスが通っている所へjawprof.jarを置きます。これで、JawprofをあなたのアプリケーションにJawprofを利用した機能を追加する準備は完了です。
Jawprofの動作設定は"jawprof.properties"ファイルで行います。また、Jakarta Commons LoggingおよびLog4J(4)にもそれぞれ、"commons-logging.properties"および"log4j.properties"が必要ですから、これらのファイルをクラスパスの通っているディレクトリに移動します。
JawprofにはシンプルなGUIツールが付属しています.このツールはデータベースに登録されているワークロード情報を確認するためのものです.
デフォルトの設定では「Technical Articles and Tips Java look and feel Graphics Repository」にあるアーカイブを利用するようになっています.ダウンロードしてクラスパスを通して使用してください.
APIの詳細についてはJawprof API 仕様を参照してください。
トランザクションの記録は全てモニタを通して行われます。jawprof.Monitor.start()
が呼ばれるとモニタリングが開始され、jawprof.Monitor.stop()
が呼ばれると、モニタは管理下から外れます。
リスト2.2.1.1[最初の例]を見てください。Monitor m = MonitorFactory.getMonitor("SAMPLE");
でモニタを獲得しています。引数のSAMPLE
がモニタIDです。この時点ではモニタリングは開始されていません。次のm.start();
によりモニタリングが開始されます。モニタはstart()
メソッドが呼ばれると、呼ばれた時点の時刻をトランザクションが開始された時刻として記録します。stop()
メソッドが呼ばれるとモニタはモニタリングの結果を記録する手続きを行います。
トランザクション種別はいつでも設定可能です。従って、jawprof.Monitor.start()
を呼ぶ時点では結果的にそのトランザクションの種別が不明でも問題ありません。jawprof.Monitor.stop()
を呼ぶ前に、jawprof.Monitor.setType(Object)
を呼びトランザクション種別を設定することが可能です。
モニタリング中にラップタイムを得ることも可能です。ラップタイムを得るにはjawprof.Monitor.lap(Object)
メソッドを使用します。引数はラップタイムのIDです。
import jawprof.*; public class Example1 { public static void main(String[] args) { Monitor m = MonitorFactory.getMonitor("SAMPLE"); m.setType("TYPE"); m.start(); m.lap("LAP0"); m.lap("LAP1"); m.stop(); } }
実行する前に設定ファイルを準備する必要があります。出力先などの設定はjawprof.properties
ファイルで行います。(5)
jawprof.properties
ファイルには全体の設定を取り扱うコンテキストクラスの設定をjawprof.context
要素で行います。通常はデフォルトの設定のjawprof.DefaultJawprofContext
で問題ないでしょう。
トランザクションプロファイリングの結果はRecorderと呼ばれるクラスにより記録されます.標準出力、CSVファイルなどのファイルへの出力、データベースへの出力がサポートされています。必要により独自のRecorderを準備することも可能です。使用するRecorderのFactoryをjawprof.recorder.factory
にて設定します。まずは標準出力に出力するjawprof.SimpleRecorder
のFactoryであるjawprof.SimpleRecorderFactory
を使用します。
jawprof.SimpleRecorder
は内部ではjawprof.FormatRecorder
の一種として定義されています。jawprof.FormatRecorder
は指定されたフォーマットでモニタリングの記録を出力先へ記録します。まずはリスト2.2.1.2[設定ファイル]のように設定してください。
# JawprofContext jawprof.context=jawprof.DefaultJawprofContext jawprof.recorder.factory=jawprof.SimpleRecorderFactory jawprof.recorder.formatrecorder.format.start={0},{1},{2},START,{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.formatrecorder.format.stop={0},{1},{2},STOP,{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.formatrecorder.format.lap={0},{1},{2},{4},{3,date,yyyy/MM/dd:HH:mm:ss:SSS}
jawprof.jar
とjawprof.properties
にクラスパスを通し、コンパイルおよび実行するとリスト2.2.3[出力例]の様に出力されます。
10901318-0,SAMPLE,TYPE,START,2004/07/18:15:24:43:070 10901318-0,SAMPLE,TYPE,STOP,2004/07/18:15:24:43:080 10901318-0,SAMPLE,TYPE,LAP1,2004/07/18:15:24:43:080 10901318-0,SAMPLE,TYPE,LAP0,2004/07/18:15:24:43:070
一つのトランザクション種別は、任意の数のトランザクショングループに所属できます。
CSVファイルに出力するにはRecorder
としてjawprof.FileRecorder
を使用します。jawprof.FileRecorder
もjawprof.FormatRecorder
の一種として定義されています。リスト2.3.1.1[CSV ファイルへの出力設定]の用にフォーマットと出力ファイルを設定します。
jawprof.context=jawprof.DefaultJawprofContext jawprof.recorder.factory=jawprof.FileRecorderFactory jawprof.recorder.formatrecorder.format.start={0},{1},{2},START,{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.formatrecorder.format.stop={0},{1},{2},STOP,{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.formatrecorder.format.lap={0},{1},{2},{4},{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.filerecorder.file.start=tran.csv jawprof.recorder.filerecorder.file.stop=tran.csv jawprof.recorder.filerecorder.file.lap=tran.csv
Jakarta Commons Loggingsを使用して出力することも可能です。jawprof.recorder.factory
にjawprof.CommonsLoggingRecorderFactory
を設定し、Jakarta Commons Loggingsの設定を行います。Jakarta Commons Loggingsの設定についてはJakarta Commons Loggingsのドキュメントを参照してください。
データベースへ保存することも可能です。データベースへ保存する場合はjawprof.recorder.factory
にjawprof.DatabaseRecorderFactory
を設定し、データベースへの接続情報を設定します。jawprof.properties
の内容はリスト2.3.3.1[データベースへの出力設定]の用になります。
jawprof.context=jawprof.DefaultJawprofContext jawprof.recorder.factory=jawprof.DatabaseRecorderFactory jawprof.recorder.databaserecorder.driver=org.gjt.mm.mysql.Driver jawprof.recorder.databaserecorder.url=jdbc:mysql:///jawprof?useUnicode=true&characterEncoding=SJIS jawprof.recorder.databaserecorder.user=user_name jawprof.recorder.databaserecorder.password=user_password
その上で、データベースの準備を行う必要があります(6)。データベースの構造を図2.3.3.1[ER 図]に示します。
各テーブルの定義は次のようになっています。
項目名 | 型 | 長さ | 少数 | 必須 | 主キー |
---|---|---|---|---|---|
ID | VARCHAR2 | 32 | - | Y | 1 |
START_TIME | TIMESTAMP | - | - | Y | |
START_TIME_MILLIS | NUMBER | 3 | 0 | Y | |
STOP_TIME | TIMESTAMP | - | - | Y | |
STOP_TIME_MILLIS | NUMBER | 3 | 0 | Y | |
TYPE | VARCHAR2 | 16 | Y |
項目名 | 型 | 長さ | 少数 | 必須 | 主キー |
---|---|---|---|---|---|
TRANSACTION | VARCHAR2 | 32 | - | Y | 1 |
ID | VARCHAR2 | 32 | - | Y | 2 |
TIME | TIMESTAMP | - | - | Y | |
TIME_MILLIS | NUMBER | 3 | 0 | Y |
項目名 | 型 | 長さ | 少数 | 必須 | 主キー |
---|---|---|---|---|---|
ID | VARCHAR2 | 16 | - | Y | 1 |
項目名 | 型 | 長さ | 少数 | 必須 | 主キー |
---|---|---|---|---|---|
TYPE | VARCHAR2 | 16 | - | Y | 1 |
GROUP | VARCHAR2 | 16 | - | Y | 2 |
非同期に記録するためにはTimerTaskRecorder
を使用します。また、標準出力とデータベースなど複数の出力先へ記録するにはMultiRecorder
を使用します。
これらを使用して標準出力とデータベースに出力する設定例をに示します。
jawprof.context=jawprof.DefaultJawprofContext jawprof.recorder.factory=jawprof.TimerTaskRecorderFactory jawprof.recorder.formatrecorder.format.start={0},{1},{2},START,{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.formatrecorder.format.stop={0},{1},{2},STOP,{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.formatrecorder.format.lap={0},{1},{2},{4},{3,date,yyyy/MM/dd:HH:mm:ss:SSS} jawprof.recorder.databaserecorder.driver=org.gjt.mm.mysql.Driver jawprof.recorder.databaserecorder.url=jdbc:mysql:///jawprof?useUnicode=true&characterEncoding=SJIS jawprof.recorder.databaserecorder.user=user_name jawprof.recorder.databaserecorder.password=user_password jawprof.recorder.multirecorder.member=jawprof.SimpleRecorderFactory,jawprof.DatabaseRecorderFactory jawprof.recorder.timertaskrecorder.factory=jawprof.MultiRecorderFactory jawprof.recorder.timertaskrecorder.interval=1000
トランザクションプロファイルとして以下のようなことができます。
SQLで集計されます。スナップショットを登録し、月末や週末に更新します。EXCELでは可能か?
Jawprofのクラス図を図3.1.1[Jawprof 基本クラス]に示す。
MonitorFactoryクラスはSingletonオブジェクトです。Monitorオブジェクトの生成/消滅を管理します。MonitorFactoryは測定した結果をRecorderオブジェクトを使用して保存します。クライアントは、getMonitor()メソッドを使用してMonitorオブジェクトを獲得します。この時、Monitor IDを引数として渡す必要があります。このIDは今測定中のMonitorを一意に識別するためのIDで測定期間全てに渡って一意なIDをクライアントが提供する必要はありません。モニタが要求されると、MonitorFactoryはトランザクションシリアルナンバーを生成します。このシリアルナンバーはSystem.currentTimeMillis() / 100000 + "-" + "シーケンス番号"で生成されます。例えば10792179-1, 10792179-2,...です。
TransactionRecordは状態を持ちます。状態は「モニタリング中(Monitoring)」と「保存中(Saving)」です。タイムアウトすると記録から消えます。MonitorはTransactionRecordの状態ごとに管理します。モニタリング中はHashMapで管理し、保存中はリストで管理します。保存中のTransactionRecordは同期/非同期に保存されます。各トランザクションレコードはキーで識別される。モニタリング中のトランザクションが重複しなければよい。
出力はjawprof.Recorderの実装クラスが行います。予め、jawprof.FileRecorderとjawprof.DatabaseRecorderの2つのabstractクラスが作成されています。jawprof.FileRecorderは任意の区切り文字で、出力を行います。JawprofではCSV形式での出力を予めサポートしています。jawprof.DatabaseRecorderはリレーショナルデータベースへの出力を行うjawprof.Recorderの実装クラスを作成するための抽象クラスです。
更新の制御は、デーモンスレッドを利用したタイマーで行われます。
の組み合わせで更新します。具体的には、JDBC接続ではjava.sql.PreparedStatement.addBatch()を使って一度に複数のレコードを登録します。
トランザクションの開始時刻、終了時刻、各ラップタイムをそれぞれ1レコードとして出力します。出力レイアウトは"<トランザクションID> <モニタID> <ラップID> <時刻>"です。開始時刻、終了時刻のラップIDは"START"と"STOP"です。時刻は"yyyy/MM/dd:HH:mm:ss"の形式で出力されます。例えば
10792509-994,994,START,2004/03/14:16:55:49
デフォルトのコンソール出力でも同様です。ただし、","がスペースに変わります。
Jawprofはそれ自身でコネクションプーリングを行いません。
データベースへのトランザクション記録の保存期間を設定することが可能です。これは定期的あるいはトリガーによって起動され、保存期間より前のレコードは削除されます。
[1] | Steve Souza. JAMon(Java Application Monitor) Users Guide. http://www.jamonapi.com/, |
[2] | 亀田寿夫、紀一誠、李頡. 性能評価の基礎と応用. 共立出版, 1998. |
[3] | http://e-words.jp/. IT 用語辞典 e-words. 株式会社インセプト, |