SPF4Jの概要

1. 概要

パフォーマンステストは、多くの場合、ソフトウェア開発サイクルの最終段階に向けてプッシュされるアクティビティです。 通常、パフォーマンスの問題のトラブルシューティングにはlink:/java-profilers[Javaプロファイラー]を使用します。
このチュートリアルでは、Simple Performance Framework for Java(SPF4J)を使用します。 コードに追加できるAPIを提供します。 その結果、*パフォーマンス監視をコンポーネントの不可欠な部分*にすることができます。

2. メトリックのキャプチャと視覚化の基本概念

始める前に、簡単な例を使用して、メトリックのキャプチャと視覚化の概念を理解してみましょう。
アプリストアで新しく起動されたアプリのダウンロードを監視することに興味があるとします。 学習のために、この実験を手動で行うことを考えてみましょう。

2.1. メトリックのキャプチャ

まず、何を測定する必要があるかを決定する必要があります。 興味のある指標は_downloads / minです。したがって、ダウンロード数を測定します。
第二に、測定を行う頻度はどれくらいですか? 「1分間に1回」を決めましょう。
最後に、どのくらい監視する必要がありますか? 「1時間」を決めましょう。
これらのルールが整ったら、実験を行う準備ができました。 実験が終了すると、結果を確認できます。
Time Cumulative Downloads    Downloads/min
----------------------------------------------
T       497                     0
T+1     624                     127
T+2     676                     52
...
T+14    19347                   17390
T+15    19427                   80
...
T+22    27195                   7350
...
T+41    41321                   11885
...
T+60    43395                   40
最初の2つの列-_time_および_cumulative downloads_-は、観察する直接値です。 3番目の列_downloads / min_は、現在のダウンロード値と以前のダウンロード値の差として計算された派生値です。 これにより、その期間の実際のダウンロード数がわかります。

2.2. メトリックの視覚化

_time_ vs _downloads / min_の単純な線形グラフをプロットしましょう。
link:/uploads/graph1-100x41.png%20100w []
いくつかの場合に発生した多数のダウンロードを示すピークがあることがわかります。 _downloads_軸に使用される線形スケールのため、低い値は直線として表示されます。
_downloads_軸を変更して、対数目盛(基数10)を使用し、対数/線形グラフをプロットしましょう。
link:/uploads/graph2-100x41.png%20100w []
ここで、実際に低い値が表示され始めます。 そして、それらは100(/-)に近づいています。 線形グラフにはピークも含まれているため、_703_の平均が示されていることに注意してください。
ピークを異常として除外する場合、対数/線形グラフを使用して実験から結論付けることができます。
  • 平均_downloads / min_は100のオーダーです

3. 関数呼び出しのパフォーマンス監視

前の例から簡単なメトリックをキャプチャして分析する方法を理解したら、それを簡単なJavaメソッド_isPrimeNumber_に適用してみましょう。
private static boolean isPrimeNumber(long number) {
    for (long i = 2; i <= number / 2; i++) {
        if (number % i == 0)
            return false;
    }
    return true;
}
SPF4Jを使用すると、メトリックをキャプチャする2つの方法があります。 次のセクションでそれらを調べてみましょう。

4. セットアップと構成

4.1. Mavenセットアップ

SPF4Jは、さまざまな目的のために多くの異なるライブラリを提供しますが、簡単な例ではいくつか必要です。
コアライブラリはhttps://search.maven.org/search?q=g:org.spf4j%20AND%20a:spf4j-core[_spf4j-core_]であり、ほとんどの必要な機能を提供します。
これをMaven依存関係として追加しましょう。
<dependency>
    <groupId>org.spf4j</groupId>
    <artifactId>spf4j-core</artifactId>
    <version>8.6.10</version>
</dependency>
パフォーマンス監視用のより適切なライブラリ– _https://search.maven.org/search?q = g:org.spf4j%20AND%20a:spf4j-aspects [spf4j-aspects]、_ _AspectJ_。
この例でこれを検討しますので、これも追加しましょう。
<dependency>
    <groupId>org.spf4j</groupId>
    <artifactId>spf4j-aspects</artifactId>
    <version>8.6.10</version>
</dependency>
最後に、SPF4Jにはデータの視覚化に非常に役立つシンプルなUIも付属しているため、https://search.maven.org/search?q = g:org.spf4j%20AND%20a:spf4j-ui [_spf4jを追加しましょう-ui_]も:
<dependency>
    <groupId>org.spf4j</groupId>
    <artifactId>spf4j-ui</artifactId>
    <version>8.6.10</version>
</dependency>

* 4.2。 出力ファイルの構成

*
SPF4Jフレームワークは、時系列データベース(TSDB)にデータを書き込み、オプションでテキストファイルに書き込むこともできます。
両方を構成して、システムプロパティ_spf4j.perf.ms.config_を設定しましょう。
public static void initialize() {
  String tsDbFile = System.getProperty("user.dir") + File.separator + "spf4j-performance-monitoring.tsdb2";
  String tsTextFile = System.getProperty("user.dir") + File.separator + "spf4j-performance-monitoring.txt";
  LOGGER.info("\nTime Series DB (TSDB) : {}\nTime Series text file : {}", tsDbFile, tsTextFile);
  System.setProperty("spf4j.perf.ms.config", "[email protected]" + tsDbFile + "," + "[email protected]" + tsTextFile);
}

* 4.3。 レコーダーとソース*

SPF4Jフレームワークのコア機能は、メトリックを記録、集計、および保存することです。これにより、分析時に後処理が不要になります。 これは、_MeasurementRecorder_および_MeasurementRecorderSource_クラスを使用して行われます。
これらの2つのクラスは、メトリックを記録する2つの異なる方法を提供します。 主な違いは、* _ MeasurementRecorder_はどこからでも呼び出すことができますが、_MeasurementRecorderSource_は注釈でのみ使用されることです。*
このフレームワークは、さまざまなタイプの集計用のレコーダーおよびレコーダーソースクラスのインスタンスを作成する_RecorderFactory_クラスを提供します。
  • createScalableQuantizedRecorder()_および
    _createScalableQuantizedRecorderSource()

  • createScalableCountingRecorder()_および
    _createScalableCountingRecorderSource()

  • createScalableMinMaxAvgRecorder()_および
    _createScalableMinMaxAvgRecorderSource()

  • createDirectRecorder()_および_createDirectRecorderSource()

    この例では、スケーラブルな量子化された集約を選択しましょう。

4.4. レコーダーの作成

最初に、_MeasurementRecorder_のインスタンスを作成するヘルパーメソッドを作成しましょう。
public static MeasurementRecorder getMeasurementRecorder(Object forWhat) {
    String unitOfMeasurement = "ms";
    int sampleTimeMillis = 1_000;
    int factor = 10;
    int lowerMagnitude = 0;
    int higherMagnitude = 4;
    int quantasPerMagnitude = 10;

    return RecorderFactory.createScalableQuantizedRecorder(
      forWhat, unitOfMeasurement, sampleTimeMillis, factor, lowerMagnitude,
      higherMagnitude, quantasPerMagnitude);
}
さまざまな設定を見てみましょう。
  • unitOfMeasurement –測定対象の単位値–
    パフォーマンス監視シナリオ、通常は時間の単位

  • sampleTimeMillis –測定を行う期間–または
    言い換えれば、測定を行う頻度

  • factor –プロットに使用される対数スケールの底
    測定値

  • lowerMagnitude –対数目盛の最小値–
    対数10、lowerMagnitude = 0は10のべき乗0 = 1を意味します

  • higherMagnitude –対数目盛の最大値–
    10を底とする_higherMagnitude_ = 4は10の4乗= 10,000を意味します

  • quantasPerMagnitude –マグニチュード内のセクションの数– a
    大きさの範囲は1,000〜10,000で、quantasPerMagnitude = 10は、範囲が10個のサブ範囲に分割されることを意味します

    必要に応じて値を変更できることがわかります。 そのため、異なる測定値に対して個別の_MeasurementRecorder_インスタンスを作成することをお勧めします。

4.5. ソースを作成する

次に、別のヘルパーメソッドを使用して、_MeasurementRecorderSource_のインスタンスを作成します。
public static final class RecorderSourceForIsPrimeNumber extends RecorderSourceInstance {
    public static final MeasurementRecorderSource INSTANCE;
    static {
        Object forWhat = App.class + " isPrimeNumber";
        String unitOfMeasurement = "ms";
        int sampleTimeMillis = 1_000;
        int factor = 10;
        int lowerMagnitude = 0;
        int higherMagnitude = 4;
        int quantasPerMagnitude = 10;
        INSTANCE = RecorderFactory.createScalableQuantizedRecorderSource(
          forWhat, unitOfMeasurement, sampleTimeMillis, factor,
          lowerMagnitude, higherMagnitude, quantasPerMagnitude);
    }
}
以前と同じ設定値を使用していることに注意してください。

4.6. 構成クラスの作成

便利な_Spf4jConfig_クラスを作成して、上記のすべてのメソッドをその中に入れましょう。
public class Spf4jConfig {
    public static void initialize() {
        //...
    }

    public static MeasurementRecorder getMeasurementRecorder(Object forWhat) {
        //...
    }

    public static final class RecorderSourceForIsPrimeNumber extends RecorderSourceInstance {
        //...
    }
}

4.7. _aop.xml_の構成

SPF4Jは、パフォーマンスの測定と監視を行うメソッドに注釈を付けるオプションを提供します。 link:/aspectj[AspectJ]ライブラリを使用します。これにより、コード自体を変更することなく、既存のコードにパフォーマンスモニタリングに必要な動作を追加できます。
ロードタイムウィーバーを使用してクラスとアスペクトを織り込み、_META-INF_フォルダーの下に_aop.xml_を配置します。
<aspectj>
    <aspects>
        <aspect name="org.spf4j.perf.aspects.PerformanceMonitorAspect" />
    </aspects>
    <weaver options="-verbose">
        <include within="com..*" />
        <include within="org.spf4j.perf.aspects.PerformanceMonitorAspect" />
    </weaver>
</aspectj>

5. _MeasurementRecorder_の使用

_MeasurementRecorder_を使用して、テスト関数のパフォーマンスメトリックを記録する方法を見てみましょう。

5.1. メトリックの記録

100個の乱数を生成し、ループでプライムチェックメソッドを呼び出しましょう。 これに先立ち、_Spf4jConfig_クラスを呼び出して初期化を行い、_MeasureRecorder_クラスのインスタンスを作成します。 このインスタンスを使用して、_record()_メソッドを呼び出して、100回の_isPrimeNumber()_呼び出しにかかった個々の時間を節約します。
Spf4jConfig.initialize();
MeasurementRecorder measurementRecorder = Spf4jConfig
  .getMeasurementRecorder(App.class + " isPrimeNumber");
Random random = new Random();
for (int i = 0; i < 100; i++) {
    long numberToCheck = random.nextInt(999_999_999 - 100_000_000 + 1) + 100_000_000;
    long startTime = System.currentTimeMillis();
    boolean isPrime = isPrimeNumber(numberToCheck);
    measurementRecorder.record(System.currentTimeMillis() - startTime);
    LOGGER.info("{}. {} is prime? {}", i + 1, numberToCheck, isPrime);
}

5.2. コードを実行する

これで、単純な関数_isPrimeNumber_()のパフォーマンスをテストする準備が整いました。
コードを実行して結果を見てみましょう。
Time Series DB (TSDB) : E:\Projects\spf4j-core-app\spf4j-performance-monitoring.tsdb2
Time Series text file : E:\Projects\spf4j-core-app\spf4j-performance-monitoring.txt
1. 406704834 is prime? false
...
9. 507639059 is prime? true
...
20. 557385397 is prime? true
...
26. 152042771 is prime? true
...
100. 841159884 is prime? false

5.3. 結果を見る

プロジェクトフォルダーからコマンドを実行して、SPF4J UIを起動しましょう。
java -jar target/dependency-jars/spf4j-ui-8.6.9.jar
これにより、デスクトップUIアプリケーションが表示されます。 次に、メニューから[__file__]> [開く]を選択します。 その後、ブラウズウィンドウを使用して_spf4j-performance-monitoring.tsdb2_ファイルを見つけて開きます。
これで、ファイル名と子アイテムを含むツリービューで新しいウィンドウが開きます。 子アイテムをクリックしてから、その上の[_Plot_]ボタンをクリックします。
これにより、一連のグラフが生成されます。
最初のグラフ_測定分布_は、前に見た対数線形グラフのバリエーションです。 このグラフには、カウントに基づいたヒートマップも表示されます。
link:/uploads/graph3.png []
2番目のグラフは、最小、最大、平均などの集約データを示しています。
link:/uploads/graph4.png []
最後のグラフは、測定値と時間のカウントを示しています。
link:/uploads/graph5-100x62.png%20100w []

6. _MeasurementRecorderSource_の使用

前のセクションでは、測定値を記録するために機能の周りに追加のコードを書く必要がありました。 このセクションでは、別のアプローチを使用してこれを回避しましょう。

6.1. メトリックの記録

最初に、メトリックをキャプチャおよび記録するために追加された余分なコードを削除します。
Spf4jConfig.initialize();
Random random = new Random();
for (int i = 0; i < 50; i++) {
    long numberToCheck = random.nextInt(999_999_999 - 100_000_000 + 1) + 100_000_000;
    isPrimeNumber(numberToCheck);
}
その定型文の代わりに、次に_ @ PerformanceMonitor_を使用して_isPrimeNumber()_メソッドに注釈を付けましょう。
@PerformanceMonitor(
  warnThresholdMillis = 1,
  errorThresholdMillis = 100,
  recorderSource = Spf4jConfig.RecorderSourceForIsPrimeNumber.class)
private static boolean isPrimeNumber(long number) {
    //...
}
さまざまな設定を見てみましょう。
  • warnThresholdMillis –メソッドの実行に許可される最大時間
    警告メッセージなし

  • errorThresholdMillis –メソッドの実行に許可される最大時間
    エラーメッセージなし* + *

  • recorderSource – _MeasurementRecorderSource_のインスタンス

6.2. コードを実行する

最初にMavenビルドを行い、次にJavaエージェントを渡してコードを実行しましょう。
java -javaagent:target/dependency-jars/aspectjweaver-1.8.13.jar -jar target/spf4j-aspects-app.jar
結果が表示されます。
Time Series DB (TSDB) : E:\Projects\spf4j-aspects-app\spf4j-performance-monitoring.tsdb2
Time Series text file : E:\Projects\spf4j-aspects-app\spf4j-performance-monitoring.txt

[DEBUG] Execution time 0 ms for execution(App.isPrimeNumber(..)), arguments [555031768]
...
[ERROR] Execution time  2826 ms for execution(App.isPrimeNumber(..)) exceeds error threshold of 100 ms, arguments [464032213]
...
SPF4Jフレームワークは、すべてのメソッド呼び出しにかかった時間を記録していることがわかります。 そして、_errorThresholdMillis_値の100ミリ秒を超えると、エラーとしてログに記録します。 メソッドに渡された引数も記録されます。

* 6.3。 結果の表示*

SPF4J UIを使用して以前に行ったのと同じ方法で結果を表示できるため、前のセクションを参照できます。

7. 結論

この記事では、メトリックをキャプチャして視覚化する基本概念について説明しました。
次に、簡単な例を使用して、SPF4Jフレームワークのパフォーマンス監視機能を理解しました。 また、組み込みのUIツールを使用してデータを視覚化しました。
いつものように、この記事の例はhttps://github.com/eugenp/tutorials/tree/master/spf4j[GitHubで]から入手できます。