wrk壓測工具實操匯總#本地壓測工具

價值說明: 利用wrk 2分鐘知曉你新開發(fā)的接口的基本性能


一、簡介

????????wrk是一個開源的、熱門的、現(xiàn)代的單機HTTP基準測試工具。它能夠在單機多核 CPU 的條件下,使用系統(tǒng)自帶的高性能 I/O 機制,如 epoll,kqueue 等,通過多線程和事件模式,對目標機器產(chǎn)生大量的負載。

????????????PS: 其實,wrk 是復用了 redis 的 ae 異步事件驅動框架,準確來說 ae 事件驅動框架并不是 redis 發(fā)明的, 它來至于 Tcl 的解釋器 jim, 這個小巧高效的框架, 因為被 redis 采用而被大家所熟知。

????????????并且內置了一個可選的Lua? JIT腳本執(zhí)行引擎,可以處理復雜的HTTP請求生成、響應處理以及自定義壓測報告。


二、跟其他壓測工具優(yōu)缺點對比

一些常用的性能測試工具,如 Apache ab,? Apache JMeter (互聯(lián)網(wǎng)公司用的較多),LoadRunner 等。

wrk 的優(yōu)勢:

????*輕量級性能測試工具; wrk的結果相比ab測試結果來說,多了一個延時直方圖,有了這個直方圖,我們可以更清晰的看到延遲的分布情況。這也是博主選擇wrk最重要的原因

????* 安裝簡單(相對 Apache ab 來說);

????* 學習曲線基本為零,幾分鐘就能學會咋用了;

? ? *基于系統(tǒng)自帶的高性能 I/O 機制,如 epoll, kqueue, 利用異步的事件驅動框架,通過很少的線程就可以壓出很大的并發(fā)量;

劣勢

????????wrk 目前僅支持單機壓測,后續(xù)也不太可能支持多機器對目標機壓測,因為它本身的定位,并不是用來取代 JMeter, LoadRunner 等專業(yè)的測試工具,wrk 提供的功能,對我們后端開發(fā)人員來說,應付日常接口性能驗證還是比較友好的。

結論:應付日常接口性能驗證還是比較友好的


三、Mac上安裝

先安裝Homebrew,安裝方式參考官網(wǎng) https://brew.sh

也可以執(zhí)行下面命令? 一鍵安裝? > /bin/bash -c "$(curl -fsSLhttps://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

安裝wrk:? >? brew install wrk

驗證是否安裝成功

> wrk -v



四、常用命令、注釋和結果分析

命令:? > wrk -t12 -c400 -d30shttp://www.baidu.com

????????這條命令表示,利用 wrk 對 www.baidu.com 發(fā)起壓力測試,線程數(shù)為 12,模擬 400 個并發(fā)請求,持續(xù) 30 秒。

詳細參數(shù)含義解析

????????常用指令說明

????????????????-c, --connections: 要保持打開的HTTP連接的總數(shù),每個線程處理數(shù)N =連接/線程

????????????????-d, --duration:? ? 測試持續(xù)時間, 如 2s, 2m, 2h

????????????????-t, --threads:? ? 測試線程總數(shù)

????????????????-s, --script:? ? ? 指定加載lua測試擴展腳本

????????????????-H, --header:? ? ? 添加請求頭信息, 如"User-Agent: wrk"

????????????????? --latency:? ? 打印延遲直方圖信息

????????????????? --timeout:? ? 如果在此時間內沒有收到響應,則記錄超時.

????????????????????????????????-開頭的指令為簡寫的,后面兩個打印延遲直方圖和超時設置沒有簡寫的,只能--開頭指定

????命令行中輸入 wrk --help, 可以看到支持以下子命令:

結果分析:



五、Get請求如何進行壓測

-- 測試指令:wrk -t16 -c100 -d5s -s review_digress_list.lua --latency htt://127.0.0.1:8081

wrk.method ="GET"?

wrk.path = "/app/{appId}/review_digress_list"

?function request()?

? ???????-- 動態(tài)生成每個請求的url?

? ???????local requestPath = string.gsub(wrk.path,"{appId}",math.random(1,10))?

? ???????-- 返回請求的完整字符串:http://127.0.0.1//app/666/review_digress_list?

? ???????return wrk.format(nil, requestPath)?

end


六、Post請求如何進行壓測

6.1、Post請求

wrk默認是采用GET請求方式進行接口測試,如果需要使用POST請求就需要使用到lua腳本,通過加載編寫好的lua腳本來進行定制化的請求。采用-s 或者 --script可以加載腳本文件。

wrk的請求構造過程主要是針對每一個線程的,所以對于壓測的環(huán)境也提供了一些函數(shù)方法來進行支持線程的環(huán)境定制化。

對于POST請求+入?yún)⒉灰恢碌慕鉀Q:

對于這種需求,我們可以通過編寫 Lua 腳本的方式,在運行壓測命令時,通過參數(shù) --script 來指定 Lua 腳本,來滿足個性化需求。

wrk 對 Lua 腳本的支持

????wrk 支持在三個階段對壓測進行個性化,分別是啟動階段、運行階段和結束階段。每個測試線程,都擁有獨立的Lua 運行環(huán)境。

? ????? 啟動階段

????????????在腳本文件中實現(xiàn) setup 方法,wrk 就會在測試線程已經(jīng)初始化,但還沒有啟動的時候調用該方法。wrk會為每一個測試線程調用一次 setup 方法,并傳入代表測試線程的對象 thread 作為參數(shù)。setup 方法中可操作該 thread 對象,獲取信息、存儲信息、甚至關閉該線程。

????????運行階段

? ? ? ? ? ? ? ?* init(args): 由測試線程調用,只會在進入運行階段時,調用一次。支持從啟動 wrk 的命令中,獲取命令行參數(shù);

? ? ? ? ? ? ? ?* delay(): 在每次發(fā)送請求之前調用,如果需要定制延遲時間,可以在這個方法中設置;

? ? ? ? ? ? ? ?* request(): 用來生成請求,每一次請求都會調用該方法,所以注意不要在該方法中做耗時的操作;

? ? ? ? ? ? ? ?* response(status, headers, body): 在每次收到一個響應時被調用,為提升性能,如果沒有定義該方法,那么wrk不會解析 headers 和 body;

? ? ? ?結束階段

? ? ? ? ? ? ? ?done() 方法在整個測試過程中只會被調用一次,我們可以從給定的參數(shù)中,獲取壓測結果,生成定制化的測試報告。

6.2、lua腳本

首先下載lua腳本 把接口+入?yún)⑻鎿Q為對應值

-- example script that demonstratesuseof setup() to pass-- data toandfrom the threadslocalcounter =1localthreads = {}function setup(thread)thread:set("id", counter) -- 設置線程id table.insert(threads, thread) -- 用threads的表格存儲counter = counter +1-- 為避免id相同,使用counter來實現(xiàn)遞增endfunction init(args) -- 注意init中初始化的值都是針對一個線程而言的!即每個線程都是隔離的requests =0-- 初始化,注意這里的初始化的變量都將成為wrk的全局變量,即后續(xù)可以直接用responses =0localmsg ="thread %d created"print(msg:format(id))end-- 全局設定 設置請求格式--wrk.method ="POST"--wrk.body ="name=zhangsan&password=123456"wrk.headers["Content-Type"] ="application/json"wrk.headers["Accept"] ="*/*"wrk.headers["Accept-Encoding"] ="gzip, deflate, br"request = function()requests = requests +1-- 構造請求數(shù),因為init中定義了,所以這里可以直接使用uid = math.random(1,10000000)method ="POST"path ="/personal/bill/queryBillDeductDetailAll"body = string.format("uid=%s&serialNo=%s&version=%s&lastId=%s",uid,20220920000108360706,519,0)returnwrk.format(method,path,nil,body)end--function request()-- requests = requests +1-- 構造請求數(shù),因為init中定義了,所以這里可以直接使用--returnwrk.request()--endfunction response(status, headers, body)responses = responses +1-- 獲取響應數(shù),因為init中定義了,所以可以直接使用endfunction done(summary, latency, requests)forindex, thread in ipairs(threads)dolocalid = thread:get("id") -- 獲取線程idlocalrequests = thread:get("requests") -- 獲取構造請求數(shù)localresponses = thread:get("responses") -- 獲取響應數(shù)localmsg ="thread %d made %d requests and got %d responses"print(msg:format(id, requests, responses)) endend

然后控制臺輸入如下命令(需要修改ip地址)

wrk -t32 -c400 -d30s -s setup.lua --latency htt://10.72.240.219:8888



七、小技巧

????如何將某個參數(shù)變成隨機參數(shù)

????????-- 動態(tài)生成每個請求的url

????????local requestPath =string.gsub(wrk.path,"{appId}",math.random(1,10))

? ????????????????? -- 返回請求的完整字符串:http://127.0.0.1//app/666/review_digress_list

????????return wrk.format(nil, requestPath)

命令行里打印日志

????local id = thread:get("id")

? ? ? ????? local requests = thread:get("requests")

? ? ? ? ????local responses = thread:get("responses")

? ? ? ????? local msg = "thread %d made %d requests and got %d responses"

????????????print(msg:format(id, requests, responses))


八、注意事項

????????wrk本身不是依賴線程數(shù)來模擬并發(fā)數(shù)的所以線程數(shù)量設置在核心數(shù)左右最好,線程數(shù)多了測試系統(tǒng)消耗大,可能帶來反效果。之前測試跟核心數(shù)一致的線程數(shù)和兩倍核心數(shù)的線程數(shù),前者壓出的QPS更高。

? ? ? ? ? ? 特別提醒:關于線程數(shù),并不是設置的越大,壓測效果越好,線程設置過大,反而會導致線程切換過于頻繁,效果降低,一般來說,推薦設置成壓測機器 CPU 核心數(shù)的 2 倍到 4 倍就行了。


有問題歡迎隨時交流

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容