1. 程式人生 > >效能測試--聯合使用jvisualVM與jmeter進行效能測試與介面效能分析

效能測試--聯合使用jvisualVM與jmeter進行效能測試與介面效能分析

在使用PerfTest進行介面的測試之後,該工具可以進行簡單的效能測試,但是對於http請求進行模擬不方便,趁這次機會,學習使用jmeter進行效能測試及分析。
之前用過jvisualVM,本次就結合jmeter一起,進行效能測試與原因分析。本篇文章分為兩大部分:工具的配置與效能分析。
開發環境:mac pro,jdk 1.8.0,mysql innoDB(測試庫,單server)

工具配置篇

1、Jmeter

1.1 使用終端開啟jmeter,此處為絕對路徑(當終端關閉時,jmeter也會一併關閉):

開啟jmeter

1.2 新建測試計劃

1.2.1 新增執行緒組

ramp-up period為執行後等待時間,設定為0則表明不暫停,一直執行;
迴圈次數若設定10,則總呼叫次數為執行緒數迴圈次數,
設定為永遠後,則在手動暫停後才會停止呼叫,否則一直執行;

新增執行緒組

設定執行緒組

1.2.2 新增&設定模擬方式

由於本次測試為模擬http請求,因此使用如下設定:

新增模擬
設定模擬

其中路徑內${phone}${openId}在後面有介紹,是本次壓力測試的引數。

1.2.3 設定引數

兩種方式,逐個手動設定與csv檔案匯入測試

1.2.3.1 逐個手動設定

新增單個引數
設定單個引數

其中新增變數即為新增引數,新增使用者即為新增一組引數列表。
1.2.3.2 csv檔案匯入

新增csv檔案
設定csv檔案格式

其中filename內的路徑為手動輸入進去的,絕對路徑,variable names為引數列表,csv格式如下:

csv檔案格式

1.2.4 檢視jmeter結果

呼叫詳情與統計結果
1.2.4.1 檢視呼叫詳情–檢視結果樹

新增結果樹

在呼叫成功之後,這裡面就會有資料,上圖左側的呼叫返回結果格式設定為json。選擇相應資料,即可看到每次請求的資料詳情。

設定結果樹

1.2.4.2 檢視統計結果–聚合報告

新增聚合報告
檢視聚合報告

2 jvisualVM

找到jdk所在安裝目錄,進入如下目錄:

進入jv目錄

2.1 設定遠端伺服器

2.1.1 由於本次使用遠端伺服器測試,需要設定遠端伺服器

新增遠端主機

2.1.2 設定jmx埠

設定jmx埠

2.1.3 查詢確定伺服器jms埠

其中在查詢jmx埠時稍微麻煩一點,由於不知道jmx或者jstatd埠,在伺服器上grep了一把(實際是在配置檔案內設定):

這裡寫圖片描述

關於jmx服務有以下配置,其中埠為10826
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=10826

2.1.4 設定抽樣器(已有測試結果)

設定抽樣器

其中抽樣器標籤為設定及資料分析,點選右上角的設定後,即可設定僅分析的檔案路徑,即服務路徑。還可設定抽樣頻率,頻率越快,自然結果越準確,但是過快可能對系統造成額外負擔,反而降低效能,這裡採用預設的100ms。
經過以上設定,基礎準備工作就做好了,下面就可以開始進行測試工作了

分析

3 測試與分析

3.1 啟動jmeter,開始測試:

啟動jmeter

其中綠色的三角標為開始執行,灰色六邊形在開始執行後即變為紅色,為停止執行按鈕,再旁邊的掃把即為清除之前的執行資料。

3.2 開始jvisualVm 取樣

開始jvisualVm 取樣

點選cpu後即開始取樣,點選停止後,再點選下方的快照,會在左側生成快照檔案,稍後可以進行具體的分析。

檢視快照

左側開啟快照檔案,檢視選擇方法,即可看到具體方法所消耗的cpu時間佔比。

3.3 設計case驗證效能

本節主要是分析原有程式碼,研究提高該介面效能的方法。但是由於涉及到程式碼邏輯,因此就不予以展開了,但是可以有一個通用的開發、優化思路進行討論分析。

3.3.1 快取。

快取這個話題有太多的點值得深入。毫無疑問,在搶紅包這種場景下,快取是必須存在的,我們如何使用好快取呢?
3.3.1.1 創立空物件,避免短期快取未命中對DB造成的壓力。
try{
    //取快取物件的值
    Object object = redisProxy.get(key,V.class);
    if(object != null && !(object instanceof NullObject)){
         …………
    }else{
        …………
        if(value != null){
            //放入快取
            redisProxy.set(key,value, Constants.EXPIRE_48H);
         }else{
            // 空物件,存放1分鐘,防刷
            redisProxy.set(key, new NullObject(), Constants.ONE_MIN);
        }
    }
}catch (Exception e){
    ……
}
這裡的NullObject即為自定義空物件,可以有效避免短期快取未命中對DB的壓力。
3.3.1.2 高併發場景(相對)穩定的資料必須使用快取。

對短期穩定的資料,可以通過設定快取有效期控制。

3.3.2 可進行本地記憶體操作的邏輯前移,涉及到DB操作、外部介面呼叫的操作則後移,降低外部依賴時間。

在進行邏輯判斷時,一般都遵循如下原則:
入參非空、合法性、正確性校驗–>資料正確性、合法性校驗–>呼叫外部介面–>DB操作–>返回

在實際操作中,可能會出現如下場景:

入參非空、合法性、正確性校驗–>資料正確性、合法性校驗–>呼叫外部介面–>DB操作–>…………資料正確性、合法性校驗–>呼叫外部介面–>DB操作–>返回

那麼在這裡,我們可以將資料正確性、合法性校驗與快取結合起來。在保證系統執行的前提下,將通過快取的資料校驗操作前置,而必須操作DB的操作後移,這樣可以在一定程度上降低DB的壓力。

若合理利用單一職責原則,將判斷邏輯與資料處理模組分離,那麼程式碼維護與邏輯擴充套件也比較容易。

3.3.3 合理使用單一職責原則

這裡只有一點,就是儘可能將判斷邏輯與資料處理邏輯分離,讓客戶端儘快拿到結果。
考慮一種場景:若判斷邏輯與資料處理分離,那麼就可以單獨提供一個類似於healthCheck的介面,快速判斷該使用者、該紅包是否可搶,而不用在進行大段的邏輯處理之後,才返回客戶端該使用者不能搶紅包。
關於這一段,我有一點體會,在上一家公司,當時有一個業務,判斷邏輯日均呼叫500w+,而處理邏輯日均才幾萬的量。那麼此時將判斷邏輯單獨行程一個介面,輕量級的,讓介面快速返回結果。而處理邏輯在進行處理前,先鎖定該資料,呼叫判斷邏輯後再進行資料處理,經過測試,1000qps(秒殺、團購開始時)仍能正常對外提供服務。

4 其他

經過以上的流程,是不是覺得此時測試已經結束了?
其實不然,web服務一般都會涉及到db,如果有時間以及業務需要,還可以持續的進行測試,觀察高qps場景下db的負載。
由於開發環境是單server的db,因此在低負載場景下,db的cpu使用率在10%左右。
而在20執行緒,450ms/每次呼叫(約40tps)的持續壓力負載下,測試庫db的cpu負載穩定在95%左右。
由於是測試庫,無法與生產環境讀寫分離的叢集資料庫相比,但是僅僅是在20執行緒持續併發訪問,開發庫的cpu負載即飆升到95%。同時,在redis服務異常時保證服務可用,將是一個值得深入的話題。