性能監控: SPF4J介紹

1. 整體介紹

性能測試是一項在軟件生命開發週期中老是被置於最後一環的活動。咱們常常依靠 Java profilers 去幫助發現性能問題。java

在這篇文章中,咱們將會學習關於 Java 的簡單性能測試框架 - SPF4J。它提供了能夠加在咱們代碼中的 API。所以,咱們能夠將 性能監視變爲咱們組件的一部分git

2. 度量捕獲和可視化的基本概念

在咱們開始以前,讓咱們用一個簡單的例子來理解度量捕獲和可視化的基本概念。github

讓咱們想象一下:咱們正關注於一款新發布的 App 在應用商店的下載量,出於學習的目的,讓咱們手工的作這件事情。web

2.1. 捕捉度量

首先咱們須要決定要測量什麼,咱們感興趣的是每分鐘下載量。 所以*,* 咱們將會測量下載量的數量。數據庫

第二,咱們多久須要執行一次測量?讓咱們 「每分鐘測量一次」吧。bash

最後,咱們應該監控多長時間?讓咱們 「監控一小時吧」。app

有了以上的這些規則,咱們就能夠實施這個實驗了。當實驗完成的時候,咱們能夠看到如下的結果:框架

時間    累積下載量                   每分鐘下載數
----------------------------------------------
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

前兩列-時間累積下載數– 咱們能夠很直觀的看到這些值。第三列,每分鐘下載量,是一個由當前和以前累積下載量的差額計算出來的間接值。咱們看到了那個時間段的實際下載數。dom

2.2. 可視化度量

讓咱們繪製一個關於 時間 vs每分鐘下載量的線形圖。maven

 

file

 

咱們能夠看到,有一些峯值代表大量的下載發生在一些場合。由於使用線性比例做爲下載量軸,因此較低的值以直線出現。

讓咱們用以 10 爲底的對數做爲下載量軸的標度,並繪製一個對數/線性圖。

 

file

 

如今咱們就能夠看到那些更低的值了。這些值在 100 上下浮動。注意,線性圖中的平均值爲 703 ,由於它也包含峯值。

若是咱們將峯值從圖像中移除,咱們可使用對數/線形圖從咱們的實驗中獲得結論:

  • 每分鐘下載量的平均值在 100 左右

3. 函數調用的性能監視

在理解了如何捕獲一個簡單的度量並從前面的例子中分析以後,讓咱們如今將它應用於一個簡單的 Java 方法 - 是不是素數

private static boolean isPrimeNumber(long number) { for (long i = 2; i <= number / 2; i++) { if (number % i == 0) return false; } return true; } 

使用 SPF4J,有兩種方法能夠捕獲指標。讓咱們在下一節中探討它們。

4. 設置和配置

4.1. Maven 設置

SPF4J 爲不一樣的性能測試提供了許多不一樣的庫,但咱們只須要一些簡單的例子。

核心庫是 [spf4j-core](search.maven.org/search?q=g:… AND a:spf4j-core),它爲咱們提供了大部分必要的功能。

讓咱們將其添加到 Maven 依賴:

<dependency>
    <groupId>org.spf4j</groupId>
    <artifactId>spf4j-core</artifactId>
    <version>8.6.10</version>
</dependency>

有一個更適合性能監控的庫 - *spf4j-aspects,*它使用的是 AspectJ

咱們將在咱們的示例中探討這一點,因此咱們也添加它:

<dependency>
    <groupId>org.spf4j</groupId>
    <artifactId>spf4j-aspects</artifactId>
    <version>8.6.10</version>
</dependency>

最後,SPF4J 還帶有一個對數據可視化很是有用的簡單 UI,因此讓咱們添加 [spf4j-ui](search.maven.org/search?q=g:… AND a: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","TSDB@" + tsDbFile + "," + "TSDB_TXT@" + tsTextFile); } 

4.3. 記錄器和來源

SPF4J 框架的核心功能是記錄,聚合和保存指標,以便在分析時不須要進行後置處理。它經過使用MeasurementRecorderMeasurementRecorderSource 類來實現。

這兩個類提供了兩種記錄度量的方法。關鍵的區別在於 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 – 幅度範圍內的部分數量 - 若是幅度範圍從 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 爲咱們提供了基於註解的性能測量和監控方法的選項。它使用 AspectJ 庫,它容許在不修改代碼自己的狀況下向現有代碼添加性能監視所需的其餘行爲。

讓咱們使用 load-time weaver 編織咱們的類和切面,並將 aop.xml 放在 META-INF 文件夾下:

<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> Open 。以後,讓咱們使用瀏覽窗口找到 spf4j-performance-monitoring.tsdb2 文件並打開它。

咱們如今能夠看到一個新窗口,其中有一個包含咱們的文件名和子項目的樹狀圖。讓咱們點擊子項目,而後點擊它上面的 Plot按鈕。

這會生成一系列圖表。

第一個圖表測量分佈是咱們以前看到的對數線性圖的變體。該圖還顯示了基於計數的熱圖。

 

file

 

第二個圖表顯示聚合數據,如最小值,最大值和平均值:

 

file

 

最後一張圖顯示了測量次數與時間的關係:

 

file

 

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 – 容許該方法在沒有錯誤消息的狀況下運行的最長時間
  • recorderSourceMeasurementRecorderSource 的一個實例

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 工具來可視化數據。與往常同樣,本文中的示例都可用 over on GitHub

原文:www.baeldung.com/spf4j

做者:Mohan Sundararaju

譯者:KeepGoingPawn

 

相關文章
相關標籤/搜索