性能測試
性能測試有兩種類型,負載測試和壓力測試:
- 負載測試(Load Testing):主要是測試軟件系統是否達到需求文檔設計的目標,如軟件在一定時期內,最大支持多少併發用戶數,軟件請求出錯率等。關注點是在滿足響應正常的條件下,請求的極限值能有多高。
- 壓力測試(Stress Testing):主要是測試硬件系統是否達到需求文檔設計的性能目標,如在一定時期內,系統的CPU利用率,內存使用率,磁盤I/O吞吐率,網絡吞吐量等。關注點是性能指標,給定一個較高的基準,系統的最好響應情況。
壓力測試
壓測時重點關注的指標:併發用戶數、TPS(每秒事務數量)、RT(事務響應時間)、事務失敗率、吞吐量、CPU(不要超過70%)和內存佔用量。
注意事項:
- 測試機與被測試機要分開
- 不要對線上的服務器做壓力測試
負載測試
負載測試
指標
性能測試時重點關注的指標數據:
- QPS,包括峯值QPS和單機QPS,
- TPS,Throughput,吞吐量:系統在單位時間內處理請求的數量
- 延遲,
- 吞吐率(Requests per second):總請求數 / 處理完成這些請求數所花費的時間
- 併發連接數(The number of concurrent users,Concurrency Level):一個用戶可能同時會產生多個會話,也即連接數
- 用戶平均請求等待時間(Time per request):處理完成所有請求數所花費的時間/ (總請求數 / 併發用戶數)
- 服務器平均請求等待時間(Time per request: across all concurrent requests):處理完成所有請求數所花費的時間 / 總請求數
總結
一般情況是沒有必要嚴格區別壓力測試和負載測試,他們的目標都是爲了評估系統的極限工作狀態或者發現系統的性能瓶頸進一步做系統性能優化,下面列舉的工具一般情況下對這兩種測試場景都是支持的。
目標
- 發現系統的指標量級和性能瓶頸;
- 進一步爲性能優化提供可視化的依據,故而最好需要壓測工具自帶生成報告的能力;
分類
性能測試,看要測試什麼對象,如代碼的執行性能,接口的耗時,單機的承載,DB的讀寫極限等,根據不同的待壓測對象使用不同的工具:;
- 代碼:JMH
- 接口:
- web:前端頁面,知識盲區;
- DB:sysbench
應用類型,
CPU密集型應用
IO密集型應用
JMH
JMeter
官網
桌面應用程序,用戶界面採用Swing Java API實現,故而跨平臺。可擴展的,提供大量的可用插件。
簡介
採樣器
Samplers,用於發送請求到不同類型的服務器。它們是每一個測試計劃的基本要素,採樣器執行基於配置請求。JMeter 5.1.1可用的採樣器列表:
訪問日誌採樣器、AJP採樣器、Bean shell取樣器、BSF採樣器、調試採樣器、FTP採樣器、HTTP採樣器、Java採樣器、JDBC採樣器、JMS(幾個)採樣器、JSR223採樣器、JUnit採樣器、LDAP採樣器、郵件閱讀器、MongoDB採樣器、操作系統進程取樣器、SMTP採樣器、SOAP、TCP採樣器、測試行動。
存在多種其他不同於JMeter插件的實現技術。每個採樣器的配置取決於它所執行的請求;這意味着一些採樣器有一些共性的配置,而另外一些採樣器由於它們各自請求的不同而完全不同。
邏輯控制器
Logic Controllers,允許你配置一個線程組內不同採樣器的執行順序。可用的邏輯控制器:
簡單控制器、循環控制器、一次性控制器、交錯控制器、隨機控制器、隨機順序控制器、流量控制器、運行時控制器、If控制器、While控制器、Switch控制器、ForEach控制器、模塊控制器、include控制器、事務控制器、記錄控制器
監聽器
Listeners,提供不同的方式查看由採樣器請求產生的結果。監聽器以報表、樹型結構、或簡明的日誌文件的形式分析結果。還可以在測試計劃中的任何地方添加監聽器,但他們只會在各自的應用範圍內解析和收集來自採樣器的數據。可用的監聽器:
樣品結果配置保存、全圖景結果集、圖表結果集、樣條線可視化工具、斷言結果集、樹形結果集、整合報告、表格結果集、簡單數據輸出、監測結果集、分佈圖(alpha)、整合圖、Mailer可視化工具、Beanshell監聽器
定時器
Timers,用來定義請求之間的等待時間。如果不指定,JMeter會一個請求完成後立即執行下一個請求,沒有任何等待時間。可用的計時器:
恆定的定時器、高斯隨機定時器、均勻隨機定時器、恆定吞吐量定時器、同步定時器、jsr223定時器、Beanshell定時器、BSF定時器、泊松隨機定時器
斷言
Assertions,通過驗證採樣器請求產生的響應,來驗證測試計劃的有效性。用來檢測被測試應用程序的響應質量。你可以爲每個測試計劃配置任何生效的斷言。可用的斷言列表:
Bean shell斷言、BSF斷言、比較斷言、jsr223斷言、響應斷言、Duration斷言、XML Assertion、BeanShell Assertion、MD5Hex Assertion、HTML Assertion、XPath Assertion、XML Schema、Assertion
Gatling
官網:https://gatling.io/
Load test as code
使用Scala語言,從代碼級別支持性能測試,能生成豐富多彩的報告,包含測試案例中收集的所有指標。同時提供腳本從命令行運行性能測試,支持錄製(record)功能。
<dependency>
<groupId>io.gatling</groupId>
<artifactId>gatling-core</artifactId>
<version>3.3.1</version>
</dependency>
每一個Gatling測試都要繼承 Simulation 類:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
class ApiGatlingSimulationTest extends Simulation {
// 定義protocol
val httpProtocol = http
.baseUrl("http://computer-database.gatling.io") // root URL for all relative URLs
.acceptHeader("text/html,application/xhtml+xml;q=0.9,*/*;q=0.8") // common headers
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
// 一個repeat對應一次模擬測試,使用{}
val scn = scenario("InjectAndGet").repeat(1000, "n") {
exec(
http("AddPerson-API")
.post("http://localhost:8080/api")
.header("Content-Type", "application/json")
.body(StringBody("""{"firstName":"John${n}","lastName":"Smith${n}","birthDate":"1980-01-01", "address":{"country":"pl","city":"Warsaw","street":"Test${n}","postalCode":"02-200","houseNo":${n}}}"""))
.check(status.is(200))
)
// 還支持這種方式:.pause(629 milliseconds)
.pause(Duration.apply(5, TimeUnit.MILLISECONDS))
}.repeat(1000, "n") {
exec(
http("GetPerson-API")
.get("http://localhost:8080/api/${n}")
.check(status.is(200))
)
}
// 30個併發用戶&測試10min
setUp(scn.inject(atOnceUsers(30))).maxDuration(FiniteDuration.apply(10, "minutes")
//.protocols(httpProtocol)
)
}
對於POST請求,除body.StringBody()
這種方式之外,還有formParam
:
.exec(
http("post-demo")
.post("/api")
.formParam("name", "Beautiful Computer") // Note the triple double quotes: used in Scala for protecting a whole chain of characters (no need for backslash)
.formParam("introduced", "2012-05-30")
)
配置maven插件:
<build>
<plugins>
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
<version>${gatling-plugin.version}</version>
<configuration>
<!-- 測試腳本 -->
<simulationClass>com.anoyi.test.ApiGatlingSimulationTest</simulationClass>
<!-- 結果輸出地址 -->
<resultsFolder>/Users/admin/code/gatling</resultsFolder>
</configuration>
</plugin>
</plugins>
</build>
執行命令:mvn gatling:execute
,生成的所有HTML報告都可以在performance-test/build/gatling-results
目錄下找到
ab
Apache Benchmark,統計功能強大。默認使用GET方法測試,
Ubuntu安裝:sudo apt-get install apache2-utils
Redhat安裝:yum -y install httpd-tools
命令格式:ab -n 100 -c 10 'http://10.34.216.49:8000/test'
常用參數:
-c,concurrency,測試併發度,即連接數
-t,測試時間,此時默認-n默認爲50000
-n,測試請求次數,一般-t或-n選一個
-p,postfile,讀取json文本request,需要一併使用-T
-u ,putfile,發送PUT請求時需要上傳的文件,需要一併使用-T
-T,Content-Type,指明請求數據格式
示例:
# 如果只用到一個Cookie,那麼只需鍵入命令:
ab -n 100 -C key=value http://test.com/
# 如果需要多個Cookie,就直接設Header:
ab -n 100 -H "Cookie: Key1=Value1; Key2=Value2" http://test.com/
比較重要的返回信息:
信息 | 示例 | 解讀 |
---|---|---|
Concurrency Level | 1000 | 併發數 |
Time per request(mean) | 465.338[ms] | 所有併發用戶都請求一次的平均時間 |
Time request | 0.247[ms] | 單個用戶請求一次的平均時間,計算全部次數的均值 |
Requests per second(mean) | 2148 | 平均每秒請求數,服務器的吞吐量 |
Percentage of the requests served within a certain time(ms) | 95% 846 | 95%的請求在846ms內返回,可看95線,99線 |
測試POST方法時,requestBody一般是json文本,需要放入txt格式文件中,且以''
括起來,使用-p -T
。
測試遇到:socket: Too many open files
時,需調整可打開文件數:ulimit -n 20480
問題:
- 無法直接在命令行測試不同URL,只能測試一個URL?
- 輸出結果格式無法修改?
wrk
官網:https://github.com/wg/wrk
wrk 只能運行在類Unix 的系統上。
git clone源碼make編譯,make成功後同目錄生成wrk文件,可複製到bin目錄。
使用:
wrk <選項> <被測HTTP服務的URL>
-c, --connections,跟服務器建立並保持的TCP連接數量
-d, --duration,壓測時間
-t,--threads,配置線程
-s, --script,指定Lua腳本路徑
-H, --header,爲每一個HTTP請求添加HTTP頭
--latency,在壓測結束後打印延遲統計信息
--timeout,超時時間
-v,--version打印正在使用的wrk的詳細版本信息
# 其中數字參數,支持國際單位 (1k, 1M, 1G)
# 其中時間參數,支持時間單位 (2s, 2m, 2h)
示例:
wrk -t8 -c200 -d30s --latency "http://www.baidu.com"
Siege
官網:http://www.joedog.org/
一款HTTP/HTTPS負載測試和基準測試工具,支持基本身份驗證、Cookie、HTTP、HTTPS和FTP協議,可配置模擬併發用戶數。
安裝:yum install siege -y
安裝成功與否,查看版本:siege -V
help文檔:
siege --help
-C, --config:查看siege當前的配置信息
-V, --version:版權說明信息
-c, --concurrent=NUM:並行啓動(訪問)用戶數,默認是10
-t, --time=NUMm:壓力測試時間,比如-t5表示持續時間是5分鐘
-b, --benchmark:基準測試,請求之間沒有延遲。
-g, --get get方式請求
-d, --delay=NUM 時間延遲,每個請求之間的延遲時間
-i, --internet 模擬用戶,隨機點擊的URL
-r, --reps=NUM:每個連接發出的請求數量,與t有些類似,兩者設置一個即可
-f, --file=FILE:對應一個文件,這個文件裏每一行爲一個URL鏈接,格式如:
-m, --mark="text" 在日誌裏標記的字符串標識
-H, --header="text" 在Header裏增加的字符串標識
-A, --user-agent="text" 在user-agent裏增加的字符串標識
-u, --url="URL",設置被測Web的URL
舉例:10個併發,每個連接10個請求,間隔1秒請求壓測。
siege -u www.baidu.com -d1 -r10 -c 10
HTTP/1.1 200 0.05 secs: 143913 bytes ==> GET /static/superman/js/lib/jquery-1-cc52697ab1.10.2.js
Transactions: 1017 hits // 總處理數量
Availability: 100.00 % // 成功請求百分百
Elapsed time: 10.06 secs //總耗時
Data transferred: 35.65 MB //總傳輸數據量
Response time: 0.03 secs // 響應時間
Transaction rate: 101.09 trans/sec // 每秒處理請求數
Throughput: 3.54 MB/sec // 吞吐量
Concurrency: 3.38 // 併發數
Successful transactions: 1017 //成功處理次數
Failed transactions: 0 //請求失敗數
Longest transaction: 0.33 // 請求最長耗時
Shortest transaction: 0.00 //請求最短耗時
Locust
使用python語言寫的分佈式的壓測工具,GitHub,有示例examples。
官網說明:
Define user behaviour with Python code, and swarm your system with millions of simultaneous users.
安裝方式其一:pip install locustio
- gevent:在Python中實現協程的第三方庫。協程又叫微線程Corouine。使用gevent可以獲取極高的併發能力;
- flask:Python的一個web開發框架,和django相當;
- requests:支持http/https訪問的庫;
- msgpack:一種快速、緊湊的二進制序列化格式,使用與類似json的數據;
- pyzmq:MQ中間件,可以把Locust運行在多個進程或多個機器(分佈式)
- geventhttpclient-wheels
- ConfigArgParse
- psutil
- Flask-BasicAuth
sysbench
模塊化,跨平臺以及多線程的DB性能測試工具