簡介
Jmeter是Apache的開源項目,基于Java開發,主要用于進行壓力測試。
優點:開源免費、支持多協議、輕量級、功能強大
官網:https://jmeter.apache.org/index.html
安裝
安裝步驟:
- 下載:進入jmeter的官網,進入Download頁面,因為是基于Java開發的,所以不分平臺,下載二進制文件即可,
- 解壓安裝包
- 修改配置文件:這是為了處理可能出現的中文亂碼問題,在bin目錄下打開jmeter.properties,將sampleresult.default.encoding的值改為UTF-8
- 配置環境變量
- 啟動jmeter:進入bin目錄,在Windows平臺下,點擊 jmeter.bat文件,啟動jmeter
- 修改語言為中文:點擊 Options - choose language - Chinese(Simplified)
用戶界面:
修改語言:
性能測試和相關指標
jmeter主要是用于做性能測試的,所以這里了解一下性能測試的相關指標
測試的分類:測試可以簡單地分為功能測試和性能測試兩種,還有自動化測試,不過它更多是一種測試技巧。
功能測試:測試單個接口的功能
-
單元測試:是程序員來操作的,測試程序中的單個單元
-
冒煙測試:測試程序最基本的功能是否正常
-
回歸測試:修改了舊代碼后,重新進行測試以確認修改沒有引入新的錯誤或導致其他代碼產生錯誤。
性能測試:
- 基準測試:單用戶測試,測試環境確定后,對業務模型中的重要業務做單獨的測試,獲取單用戶運行時的各項性能指標。在某個時刻,通過基準測試,建立一個已知的性能基準線,當系統的軟硬件環境發生變化之后再進行一次基準測試,以確定變化對性能的影響
- 負載測試:通過逐步增加系統負載,確定在滿足系統的性能指標情況下,找出系統能夠承受的最大負載量的測試
- 穩定性測試:在服務器穩定運行的情況下,進行長時間測試,并最終保證服務器能滿足線上業務需求。
- 并發測試:在極短的時間內,發送多個請求,來驗證服務器對并發的處理能力
- 壓力測試:在強負載下的測試,查看系統在峰值情況下,是否功能隱患、系統是否具有良好的容錯能力和可恢復能力
- 性能測試:通過特定的方式對被測試系統按照一定測試策略施加壓力,獲取該系統的響應時間、TPS、吞吐量、資源利用率等性能指標,來檢測系統上線后能否滿足用戶需求的過程。
自動化測試:編寫測試腳本,通過邏輯控制器和關聯等功能,測試一系列接口的功能。
性能測試的相關指標:
- QPS:Queries Per Second,每秒查詢率,一臺服務器每秒鐘能夠執行的查詢次數,代表了最大吞吐量
- TPS:Transactions Per Second,吞吐量,每秒事務數,一個事務指客戶端發送請求并且接收到響應的過程,客戶機在發送請求時開始計時,收到服務器響應后結束計時,以此來計算使用的時間和完成的事務個數。
- 并發數:指系統同時能處理的請求數量,同時反應了系統的負載能力。這個數值可以分析機器1秒內的訪問日志數量來得到
衡量網站的性能指標
- 響應時間:從開始發送請求到接收到響應所花費的時間
- 并發數:系統同時能處理的請求數量
- 并發連接數:每秒鐘服務器連接的總TCP數量
- 請求數:Query Per Second,每秒多少請求
- 事務數:TPS,每秒事務數
- 并發用戶數:單位時間內有多少用戶
- 吞吐量:單位時間內系統能處理的請求數量
大型互聯網項目架構目標
- 高性能:提供快速的訪問體驗
- 高可用:網站服務一直可以正常訪問
- 可伸縮:通過增加硬件,來提升處理能力
- 可擴展:模塊間的耦合度低,
- 安全性:網站能夠承受住外部攻擊
性能測試的兩件事情:模擬巨大負載、生成測試報告
入門案例
在這里,通過一個入門案例來了解jmeter的基本使用。
準備工作
編寫一個springboot項目,作為本次測試的目標。
pom.xml:
<groupId>org.example</groupId>
<artifactId>learn_jmeter</artifactId>
<version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties><!--springboot工程需要繼承的父工程-->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.8.RELEASE</version><relativePath />
</parent><dependencies><!--web開發的起步依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>
控制器:
@RestController
@RequestMapping("/hello")
public class HelloController {private static final Logger LOG = LoggerFactory.getLogger(HelloController.class);private static int i = 1;@GetMapping("/h1")public String s1() {LOG.info("第 {} 次請求", i++);return "success";}
}
開始測試
jmeter中的兩個基本概念:
- 測試計劃:jmeter中所有的測試內容都要放在測試計劃之下
- 線程組:一個線程就代表一個用戶。
配置測試計劃:
- 在測試計劃內添加線程組:右擊測試計劃,點擊 添加 - 線程(用戶) - 線程組,線程組用于發起請求,配置線程組可以設定發起請求的次數。
- 線程組內添加取樣器:右擊線程組 - 添加 - 取樣器 - HTTP請求,將之前準備好的接口的相關信息填寫進去。取樣器表示發起什么樣的請求,在這里選擇發起http請求。
- 線程組內添加查看結果樹:右測試計劃 - 添加 - 監聽器 - 查看結果樹,不需要配置查看結果樹
開始測試:點擊左上角菜單欄中的運行按鈕,開啟測試,點擊查看結果樹,可以看到每個請求的統計數據
保存測試計劃:點擊 文件 - 保存,測試計劃會被保存為jmx文件,下次直接從文件中打開即可。實際上開始測試的時候,jmeter就會提醒用戶保存測試計劃。
springboot中接收到的請求:
總結:
- jmeter中所有的測試內容都需要放到測試計劃中
- 線程組是測試計劃的基本單位,線程組的一個線程代表一個用戶,可以配置線程數和每個線程的循環次數,也就是用戶執行幾次操作
- 每一個測試計劃都必須有一個取樣器和監聽器:取樣器用于發送請求并且接收響應,監聽器用于查看結果,http請求組件是一個取樣器,查看結果數樹組件是一個監聽器
查看性能測試的相關結果
之前的測試流程,只是簡單地使用jmeter發送了一個http請求,并且可以查看結果,接下來,使用jmeter來做壓力測試,并且查看壓力測試的相關結果指標。
第一步:配置線程組:線程數設置為10個,循環100次
第二步:添加監聽器 - 聚合報告,這是最簡單的監聽器,可以查看性能測試的相關指標。
第三步:開始測試。
第四步:查看結果
結果分析:
- Label:采樣器的名稱,例如HTTP請求的Name;
- 樣本:發送請求的數量
- 平均值:平均響應時間(單位:ms);默認是單個Request的平均響應時間,當使用了Transaction Controller時,也可以以Transaction為單位顯示平均響應時間;
- 中位數:50%的用戶響應時間小于這個值;
- 95%百分位:95%的用戶響應時間小于這個值;
- 99%百分位:99%的用戶響應時間小于這個值;
- 最小值:用戶響應時間最小值;
- 最大值:用戶響應時間最大值;
- 異常%:測試出現的錯誤請求數量百分比;請求的錯誤率 = 錯誤請求的數量/請求的總數;若出現錯誤就要看服務端的日志查找定位原因;
- 吞吐量:Throughput簡稱TPS,吞吐量,默認情況下表示每秒處理的請求數,也就是指服務器處理能力,TPS越高說明服務器處理能力越好;
- KB/sec:每秒從服務器端接收到的數據量;
jmeter中的核心概念
測試計劃和線程組
測試計劃:存放所有的測試內容,相當于一個項目的根目錄
線程組:對于線程進行分類,線程組是測試計劃的基本單位,線程組中的每一個線程都代表一個用戶
- 線程組的屬性
- 名稱
- 注釋
- 在取樣器錯誤后要執行的動作:默認選擇繼續,還有啟動下一進程循環、停止線程、停止測試
- 線程數
- Ramp-Up時間:準備時長,設置的線程數需要多長時間全部啟動。如果線程數為10,準備時長為2,那么需要2秒鐘啟動10個線程,也就是每秒鐘啟動5個線程。
- 循環次數:1個線程執行幾次
- 延遲創建線程直到需要
- 調度器
- 持續時間:如果循環次數是永遠,持續時間會被應用,表示持續多少秒后線程結束
- 啟動延遲:線程在幾秒之后啟動
- 線程組的執行順序
- 并發執行:多個線程同時執行,默認是并發執行
- 順序執行:多個線程順序執行,在最頂層的測試計劃界面,勾選獨立運行每個線程組,就可以開啟順序執行
- 特殊的線程組
- setUp線程組:最優先執行的線程組,創建方式也是 右擊 執行計劃,點擊 添加 - 線程(用戶)- setUp線程組
- tearDown線程組:最后執行的線程組,創建方式類似于setUp線程組
組件和元件
組件:實現單獨的某個功能,有取樣器、監聽器等。
元件:多個類似功能組件的容器。元件也可以理解為組件的一種,下面把它們統稱為組件
jmeter中的組件
在之前的入門案例中,接觸了取樣器和監聽器,它們是jmeter中發送請求和分析響應的基本組件,jmeter還提供了許多其它組件,支持把一系列的請求組合起來,模擬用戶的行為。
jmeter中的基本組件:
-
取樣器:向服務器發送請求并接收響應的最小單位,jmeter支持不同的取樣器,通過這些取樣器,jmeter可以支持多種協議,常用的取樣器有HTTP取樣器、JDBC取樣器、FTP取樣器
-
監聽器:對測試結果進行處理和可視化展示的一系列組件,常用的監聽器有查看結果樹、聚合報告
用于增強取樣器的組件:
-
配置元件:配置其它組件的相關信息,常見的配置元件:HTTP信息頭管理器、CSV數據配置、用戶自定義變量
-
邏輯控制器:控制取樣器執行順序的組件,常用的邏輯控制器:if控制器、foreach控制器、循環控制器
-
定時器:在操作之前設置等待時間,常見的定時器:同步定時器、常量和吞吐量定時器
-
前置處理器:用于取樣器執行之前對請求進行處理
-
后置處理器:用于取樣器執行之后對得到的響應進行處理,常見的后置處理器:JSON提取器、正則表達式提取器、Xpath提取器
用于增強監聽器的組件:
- 斷言:對響應結果進行判斷,場景的斷言組件:響應斷言、大小斷言、JSON斷言、
組件的作用域:組件可以被配置到測試計劃下,也可以被配置到線程組下,被配置到哪里,作用域就是哪里。
組件的執行順序
-
同一作用域下不同組件執行順序:配置元件 --> 前置處理器 --> 定時器 --> 取樣器 --> 后置處理器 --> 斷言 --> 監聽器
-
同一作用域下相同組件的執行順序:從上到下依次執行
使用案例
在這里,通過實際的需求來學習jmeter中的常用組件
需求1:為HTTP請求添加請求頭
這個需求需要使用http信息頭管理器來完成。
http信息頭管理器:配置元件的一種,配置HTTP協議的請求頭
- 作用域:如果位于測試計劃目錄內,作用于測試計劃下的所有線程組,如果位于線程組內,作用于線程組
案例:
需求2:把多個http請求的相同信息提取出來,集中管理
實現這個功能,需要使用“http請求默認值”組件
http請求默認值:配置元件的一種,作用是管理多個http請求的相同信息。
- 使用步驟:把多個http請求的相同信息寫入到當前組件中,然后,在同一個測試計劃下,新創建的HTTP請求就不再需要填寫公共信息
案例:
需求3:把多處使用到的數據提取為變量,集中管理
這個需求使用“用戶自定義變量”來實現。
用戶自定義變量:配置元件的一種,在當前組件中配置鍵值對,在其它地方,使用 ${變量名} 的方式來引用變量
- 優點:通過用戶自定義變量,來實現參數化。參數化是指動態地獲取、設置或生成數據,是一種由程序驅動代替人工驅動的數據設計方案,提高腳本的編寫效率和編寫質量
案例:
- 配置變量:
- 使用變量:
需求4:發送10個請求,要求每個請求都有自己獨立的數據
實現這個功能,需要從csv文件中讀取數據,這需要使用“CSV 數據文件設置”
CSV數據文件設置:配置元件的一種,用戶如果想要把數據放到csv文件中,需要使用當前組件。
-
使用方式:配置csv文件的文件名、文件編碼、字段名稱、分隔符,然后線程每執行一次,就會去csv文件中讀取一行數據,用戶再使用 ${變量名} 來引用csv文件中的數據。
-
優點:通過從csv文件中讀取數據,把測試數據和測試腳本分離,使得測試用例更加靈活,并且可以實現參數化
案例:
- 設置csv文件的屬性
- csv文件中的內容
- 引用csv文件中的數據
注意:
- 編寫csv文件:文件中不能有表頭,第一行就是數據,字段之間以逗號分割,文件使用utf-8編碼。也可以使用txt文件來代替,因為csv文件本身就是普通的文本文件
- csv文件的局限性:字段中不能出現分隔符,使用反斜杠轉義也不可以
- 配置線程的運行次數:線程運行一次,讀取jmeter中的一行數據,下一次運行時讀取下一行,所以運行次數最好和csv文件中的行數相對應,
使用csv文件時線程組的配置方式
在上面的案例中,需要把csv文件中的行數和線程的運行次數對應起來,才能保證線程正好能讀取完csv文件中的數據,但是這樣在實際使用過程中會很麻煩,所以現在提供一種方式,使得線程組可以在讀取完csv文件后自動結束。
配置方式:
-
第一步:在線程組界面:配置線程的循環次數為永遠
-
第二步:在CSV數據文件設置界面:
- 配置”遇到文件結束符再次循環“為false,表示只讀取一次;
- 配置”遇到文件結束符停止線程“ 為true,因為之前已經配置了線程的循環次數為永遠,所以在這里,當csv文件被讀取完時,線程就會停止循環
案例:
- 線程組界面
- csv設置界面
需求5:判斷請求結果是否正確
這個需要需要使用“斷言”來實現。
斷言:用于判斷請求結果的組件。斷言和取樣器類似,它們是平級關系,斷言功能包含一系列組件,每個組件都可以執行不同類型的斷言,包括JSON斷言、大小斷言等
案例:配置一個json斷言,判斷返回值中code字段的值是200.
- 配置方式:
- 斷言結果
需求6:獲取上一個請求返回的數據
需求:用戶成功登錄后,服務器會返回一個token,用戶使用這個token,可以查看當前用戶的詳細信息。
實現這個需求,需要使用后置處理器下的JSON提取器。
后置處理器:在請求完成之后對響應結果進行處理。
案例:在這里使用后置處理器中的JSON提取器,提取服務端返回的json數據,把數據放到變量中,然后在下一個請求中引用變量。
第一步:配置請求的后置處理器,需要在取樣器節點下添加后置處理器,只有這樣后置處理器才能作用于取樣器
第二步:在第二個請求中引用后置處理器中的變量
需求7:如果上一個請求不正確,下一個請求不執行
需求:用戶登錄成功后會返回一個token,在這里需要判斷,如果用戶沒有登錄成功,那么就不執行下一個請求。
實現這個功能,需要使用邏輯控制器。
邏輯控制器:控制它內部所有取樣器的執行流程,取樣器需要是邏輯控制器的子節點,然后才能生效。
案例:在這里選擇使用邏輯控制器中的IF控制器來實現這個功能,將下一個請求放到IF控制器之中。
- 配置IF控制器:
注意,要取消勾選Interpret選項,在案例中使用到的變量是上一個節點的JSON提取器中提取出來的。
需求8:上傳文件
需求:使用jmeter的http取樣器,發送上傳文件的請求
實現這個需求,需要使用http取樣器中的“文件上傳”tab,輸入文件名、http請求中文件對應的參數即可。
案例:
需求9:后置處理器之正則表達式
需求:在http請求的響應中,會返回一個url,現在需要解析出這個url中的路徑信息。
實現這個需求,需要使用后置處理器中的正則表達式提取器,配置正則表達式,提取數據中的內容
案例:
案例講解:
- 第一步:配置需要從響應的哪部分中提取數據
- 第二步:配置提取出的數據存儲到哪個變量中
- 第三步:配置正則表達式,要注意,提取的數據是正則表達式中被括號包裹的數據,相當于分組匹配,在這里的正則表達式是
https?://[^/]+(/[^?]+)
,這個正則表達式用于提取url中的路徑部分 - 第四步:模板,表示提取正則表達式中第幾個分組的數據,在這里是
$1$
,表示提取正則表達式中第一個括號中的數據。
擴展:提取正則表達式中的最后一節路徑:https?://[^/]+/?.*/([^?]+)
需求10:if控制器 判斷變量是10的倍數
在if控制器中寫上表達式:${__jexl3(${pageNo} % 10 == 0)}
,在這里,pageNo就是變量
需求11:循環控制器和計數器
循環控制器是邏輯控制器的一種,計數器是配置元件的一種,聯合使用,可以有for循環的效果,但是要注意,計數器必須放在循環控制器中才會在循環控制器的范圍內生效。
需求12:跨線程共享變量
實現這個需求的步驟:
- 第一步:添加一個后置處理器,叫做BeanShell,在里面寫入代碼:
${__setProperty(var, ${var})}
,在這里,var是要被跨線程共享的變量 - 第二步:在其它線程中引用當前變量:
${__P(var)}
原理:在jmeter中,變量是線程共享的,屬性是全局共享的,這里把變量設置為一個屬性了。
需求13:每兩秒鐘發送一次請求
使用 定時器 - 固定定時器
來做
需求14:從json中提取出一個數組然后遍歷這個數組
實現這個需求的步驟:
- 第一步:配置一個JSON提取器,難點在與JSON提取器中路徑的配置,這里提供一個案例:
$.data[*].avatar
,表示提取data中所有名為avatar
的變量,并且注意Match No
輸入-1,表示提取所有變量。 - 第二步:配置ForEach控制器,有幾個輸入性:
- 變量前綴:JSON提取器中設置的變量,
- 開始循環字段:0
- 結束循環字段:
${__javaScript(${變量名_matchNr})}
,這是jmeter提供的變量 - 輸出變量名稱:forEach控制器輸出的變量名稱
- 第三步:在ForEach控制器的內部使用變量。
其它常用組件
定時器:可以實現時間模式相關的性能測試。
- 同步定時器:Synchronized Timer,用來保證取樣器在同一時刻向服務器發起負載
- 常量吞吐量定時器:高頻率的訪問服務器,1s鐘訪問多少次,持續多少秒,
取樣器:
- 數據庫取樣器:直連數據庫,向數據庫發送請求并接收響應
在命令行運行腳本
Jmeter有兩種運行模式:
- GUI模式:主要用來編寫和調試測試腳本
- 命令行模式:對負載機的資源消耗會更小,用來實現高并發和壓力測試
在命令行執行測試腳本:jmeter -n -t ${scriptFile} -l ${logFile} -e -o ${dir}
- 參數講解
- -n 無圖形化運行
- -t 被運行的腳本
- -l 將運行信息寫入日志文件
- -e 生成測試報告
- -o 指定報告輸出目錄
案例:jmeter -n -t blog-api_最熱文章.jmx -l j.log -e -o output
,在output目錄下可以查看jmeter生產的html文件。
D:\apache-jmeter-5.5>jmeter -n -t blog-api_最熱文章.jmx -l j.log -e -o output
Creating summariser <summary>
Created the tree successfully using blog-api_.jmx
Starting standalone test @ April 6, 2024 4:41:58 PM CST (1712392918522)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary + 121 in 00:00:01 = 101.8/s Avg: 53 Min: 10 Max: 155 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
summary + 879 in 00:00:04 = 201.7/s Avg: 47 Min: 6 Max: 127 Err: 0 (0.00%) Active: 0 Started: 10 Finished: 10
summary = 1000 in 00:00:06 = 180.2/s Avg: 47 Min: 6 Max: 155 Err: 0 (0.00%)
Tidying up ... @ April 6, 2024 4:42:04 PM CST (1712392924365)
... end of run
性能測試結果報表:html文件
message on port 4445
summary + 121 in 00:00:01 = 101.8/s Avg: 53 Min: 10 Max: 155 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
summary + 879 in 00:00:04 = 201.7/s Avg: 47 Min: 6 Max: 127 Err: 0 (0.00%) Active: 0 Started: 10 Finished: 10
summary = 1000 in 00:00:06 = 180.2/s Avg: 47 Min: 6 Max: 155 Err: 0 (0.00%)
Tidying up … @ April 6, 2024 4:42:04 PM CST (1712392924365)
… end of run
性能測試結果報表:html文件[外鏈圖片轉存中...(img-Qb2zCm3f-1743754695159)]