被面試官常常問到以前開發的系統接口 QPS 能達到多少,又給不出一個數值,支支吾吾,致使總體面試效果下降?html
緣由基本是一些公司中,作完功能測試就完了,壓根不會有性能測試這一步,或者說併發量較少,沒有必要進行性能測試,亦或者,交給測試人員後,只要總體問題不大,測試報告通常也是不會再給後端人員看的,這就致使咱們在面試的時候,場面一度尷尬 !!!git
其實,不僅僅是針對面試,做爲一名後端開發者,咱們在完成一個接口開發後,在交給測試工程師以前,常常也會想知道,本身寫的這個接口的性能如何呢?吞吐量能達到多少?QPS(Query per second 每秒處理完的請求數) 能達到多少呢?github
這個時候,咱們就須要藉助一些經常使用的性能測試工具,如 Apache ab, Apache JMeter (互聯網公司用的較多),LoadRunner 等。面試
咱們今天主要說一說輕量級性能測試工具 wrk。redis
1、什麼是 wrk 2、 wrk 的優點&劣勢後端
2.1 優點centos
2.2 劣勢bash
3、wrk 安裝服務器
3.1 Linux 安裝多線程
3.2 MacOS 安裝
3.3 Window 10 安裝
3.4 驗證一下,是否安裝成功
4、如何使用
4.1 簡單使用
4.2 wrk 子命令參數說明
4.3 測試報告
4.4 使用 Lua 腳本進行復雜測試
5、總結 6、參考文檔
摘自官方 GitHub 上的英文介紹:
翻譯一下:
wrk 是一款針對 Http 協議的基準測試工具,它可以在單機多核 CPU 的條件下,使用系統自帶的高性能 I/O 機制,如 epoll,kqueue 等,經過多線程和事件模式,對目標機器產生大量的負載。
PS: 其實,wrk 是複用了 redis 的 ae 異步事件驅動框架,準確來講 ae 事件驅動框架並非 redis 發明的, 它來至於 Tcl 的解釋器 jim, 這個小巧高效的框架, 由於被 redis 採用而被你們所熟知。
在說 wrk 的優點以前,瞅一下 wrk 的 GitHub Star 數,也能側面反映下它的可靠性:
Wow ! 截止筆者截圖爲止, Star 數已經達到了 19742 !!!
再來講說 wrk 的優點:
輕量級性能測試工具;
安裝簡單(相對 Apache ab 來講);
學習曲線基本爲零,幾分鐘就能學會咋用了;
基於系統自帶的高性能 I/O 機制,如 epoll, kqueue, 利用異步的事件驅動框架,經過不多的線程就能夠壓出很大的併發量;
wrk 目前僅支持單機壓測,後續也不太可能支持多機器對目標機壓測,由於它自己的定位,並非用來取代 JMeter, LoadRunner 等專業的測試工具,wrk 提供的功能,對咱們後端開發人員來講,應付平常接口性能驗證仍是比較友好的。
wrk 只能被安裝在類 Unix 系統上,因此咱們須要一個 Linux 或者 MacOS 環境。Windows 10 安裝須要開啓自帶的 Ubuntu 子系統。
依次執行以下命令:
sudo apt-get install build-essential libssl-dev git -y git clone https://github.com/wg/wrk.git wrk cd wrk make # 將可執行文件移動到 /usr/local/bin 位置 sudo cp wrk /usr/local/bin
依次執行以下命令:
sudo yum groupinstall 'Development Tools' sudo yum install -y openssl-devel git git clone https://github.com/wg/wrk.git wrk cd wrk make # 將可執行文件移動到 /usr/local/bin 位置 sudo cp wrk /usr/local/bin
Mac 系統也能夠經過先編譯的方式來安裝,可是更推薦使用 brew
的方式來安裝, 步驟以下:
安裝 Homebrew,安裝方式參考官網 https://brew.sh (也就一行命令的事);
安裝 wrk: brew install wrk
;
Windown 10 須要在 Windows功能
裏勾選 適用於Linux的Windows子系統
, 而後經過 bash
命令切換到 Ubuntu 子系統。接下來,參考3.1.1 Ubuntu 的操做系通中,安裝 wrk 的步驟。
因爲筆者使用的是 MacOS, Windows 上的安裝步驟,並無實際操做過,具體安裝步驟,您能夠參考官方 Windows 10 的安裝教程:https://github.com/wg/wrk/wiki/Installing-wrk-on-Windows-10 ,或者用您喜歡的搜索引擎來搜索 Windows 10 如何啓用 Ubuntu 子系統後,再安裝 wrk,亦或者經過安裝 Linux 虛擬機的方式來使用 wrk。
命令行中輸入命令:
wrk -v
輸出如上信息,說明安裝成功了!
安裝成功了,要如何使用呢?
wrk -t12 -c400 -d30s http://www.baidu.com
這條命令表示,利用 wrk 對 www.baidu.com 發起壓力測試,線程數爲 12,模擬 400 個併發請求,持續 30 秒。
除了上面簡單示例中使用到的子命令參數, wrk
還有其餘更豐富的功能,命令行中輸入 wrk--help
, 能夠看到支持如下子命令:
[root@VM_0_5_centos ~]# wrk --help
Usage: wrk <options> <url>
Options:
-c, --connections <N> Connections to keep open
-d, --duration <T> Duration of test
-t, --threads <N> Number of threads to use
-s, --script <S> Load Lua script file
-H, --header <H> Add header to request
--latency Print latency statistics
--timeout <T> Socket/request timeout
-v, --version Print version details
Numeric arguments may include a SI unit (1k, 1M, 1G)
Time arguments may include a time unit (2s, 2m, 2h)
翻譯一下:
使用方法: wrk <選項> <被測HTTP服務的URL>
Options:
-c, --connections <N> 跟服務器創建並保持的TCP鏈接數量
-d, --duration <T> 壓測時間
-t, --threads <N> 使用多少個線程進行壓測
-s, --script <S> 指定Lua腳本路徑
-H, --header <H> 爲每個HTTP請求添加HTTP頭
--latency 在壓測結束後,打印延遲統計信息
--timeout <T> 超時時間
-v, --version 打印正在使用的wrk的詳細版本信息
<N>表明數字參數,支持國際單位 (1k, 1M, 1G)
<T>表明時間參數,支持時間單位 (2s, 2m, 2h)
PS: 關於線程數,並非設置的越大,壓測效果越好,線程設置過大,反而會致使線程切換過於頻繁,效果下降,通常來講,推薦設置成壓測機器 CPU 核心數的 2 倍到 4 倍就好了。
執行壓測命令:
wrk -t12 -c400 -d30s --latency http://www.baidu.com
執行上面的壓測命令,30 秒壓測事後,生成以下壓測報告:
Running 30s test @ http://www.baidu.com 12 threads and 400 connections Thread Stats Avg Stdev Max +/- Stdev Latency 386.32ms 380.75ms 2.00s 86.66% Req/Sec 17.06 13.91 252.00 87.89% Latency Distribution 50% 218.31ms 75% 520.60ms 90% 955.08ms 99% 1.93s 4922 requests in 30.06s, 73.86MB read Socket errors: connect 0, read 0, write 0, timeout 311 Requests/sec: 163.76 Transfer/sec: 2.46MB
咱們來具體說一說,報告中各項指標都表明什麼意思:
Running 30s test @ http://www.baidu.com (壓測時間30s) 12 threads and 400 connections (共12個測試線程,400個鏈接) (平均值) (標準差) (最大值)(正負一個標準差所佔比例) Thread Stats Avg Stdev Max +/- Stdev (延遲) Latency 386.32ms 380.75ms 2.00s 86.66% (每秒請求數) Req/Sec 17.06 13.91 252.00 87.89% Latency Distribution (延遲分佈) 50% 218.31ms 75% 520.60ms 90% 955.08ms 99% 1.93s 4922 requests in 30.06s, 73.86MB read (30.06s內處理了4922個請求,耗費流量73.86MB) Socket errors: connect 0, read 0, write 0, timeout 311 (發生錯誤數) Requests/sec: 163.76 (QPS 163.76,即平均每秒處理請求數爲163.76) Transfer/sec: 2.46MB (平均每秒流量2.46MB)
能夠看到,壓測報告仍是很是直觀的!
標準差啥意思?標準差若是太大說明樣本自己離散程度比較高,有可能系統性能波動較大。
您可能有疑問了,你這種進行 GET 請求還湊合,我想進行 POST 請求咋辦?並且我想每次的請求參數都不同,用來模擬用戶使用的實際場景,又要怎麼弄呢?
對於這種需求,咱們能夠經過編寫 Lua 腳本的方式,在運行壓測命令時,經過參數 --script
來指定 Lua 腳本,來知足個性化需求。
wrk 支持在三個階段對壓測進行個性化,分別是啓動階段、運行階段和結束階段。每一個測試線程,都擁有獨立的Lua 運行環境。
啓動階段:
function setup(thread)
在腳本文件中實現 setup 方法,wrk 就會在測試線程已經初始化,但尚未啓動的時候調用該方法。wrk會爲每個測試線程調用一次 setup 方法,並傳入表明測試線程的對象 thread 做爲參數。setup 方法中可操做該 thread 對象,獲取信息、存儲信息、甚相當閉該線程。
thread.addr - get or set the thread's server address thread:get(name) - get the value of a global in the thread's env thread:set(name, value) - set the value of a global in the thread's env thread:stop() - stop the thread
運行階段:
function init(args) function delay() function request() function response(status, headers, body)
init(args)
: 由測試線程調用,只會在進入運行階段時,調用一次。支持從啓動 wrk 的命令中,獲取命令行參數;
delay()
: 在每次發送請求以前調用,若是須要定製延遲時間,能夠在這個方法中設置;
request()
: 用來生成請求, 每一次請求都會調用該方法,因此注意不要在該方法中作耗時的操做;
response(status,headers,body)
: 在每次收到一個響應時被調用,爲提高性能,若是沒有定義該方法,那麼wrk不會解析 headers
和 body
;
結束階段:
function done(summary, latency, requests)
done() 方法在整個測試過程當中只會被調用一次,咱們能夠從給定的參數中,獲取壓測結果,生成定製化的測試報告。
自定義 Lua 腳本中可訪問的變量以及方法:
變量:wrk
wrk = { scheme = "http", host = "localhost", port = 8080, method = "GET", path = "/", headers = {}, body = nil, thread = <userdata>, }
以上定義了一個 table
類型的全局變量,修改該 wrk
變量,會影響全部請求。
方法:
wrk.fomat
wrk.lookup
wrk.connect
上面三個方法解釋以下:
function wrk.format(method, path, headers, body)
wrk.format returns a HTTP request string containing the passed parameters
merged with values from the wrk table.
# 根據參數和全局變量 wrk,生成一個 HTTP rquest 字符串。
function wrk.lookup(host, service)
wrk.lookup returns a table containing all known addresses for the host
and service pair. This corresponds to the POSIX getaddrinfo() function.
# 給定 host 和 service(port/well known service name),返回全部可用的服務器地址信息。
function wrk.connect(addr)
wrk.connect returns true if the address can be connected to, otherwise
it returns false. The address must be one returned from wrk.lookup().
# 測試給定的服務器地址信息是否能夠成功建立鏈接
調用 POST 接口:
request = function() uid = math.random(1, 10000000) path = "/test?uid=" .. uid return wrk.format(nil, path) end
注意: wrk 是個全局變量,這裏對其作了修改,使得全部請求都使用 POST 的方式,並指定了 body 和 Content-Type頭。
自定義每次請求的參數:
request = function() uid = math.random(1, 10000000) path = "/test?uid=" .. uid return wrk.format(nil, path) end
在 request 方法中,隨機生成 1~10000000 之間的 uid,並動態生成請求 URL.
每次請求前,延遲 10ms:
function delay() return 10 end
請求的接口須要先進行認證,獲取 token 後,才能發起請求,咋辦?
token = nil
path = "/auth"
request = function()
return wrk.format("GET", path)
end
response = function(status, headers, body)
if not token and status == 200 then
token = headers["X-Token"]
path = "/test"
wrk.headers["X-Token"] = token
end
end
上面的腳本表示,在 token 爲空的狀況下,先請求 /auth
接口來認證,獲取 token, 拿到 token 之後,將 token 放置到請求頭中,再請求真正須要壓測的 /test
接口。
壓測支持 HTTP pipeline 的服務:
init = function(args)
local r = {}
r[1] = wrk.format(nil, "/?foo")
r[2] = wrk.format(nil, "/?bar")
r[3] = wrk.format(nil, "/?baz")
req = table.concat(r)
end
request = function()
return req
end
經過在 init 方法中將三個 HTTP請求拼接在一塊兒,實現每次發送三個請求,以使用 HTTP pipeline。
本文中,咱們學習了輕量級性能測試工具 wrk, 如何安裝,以及具體的使用方法,包括經過 Lua 腳原本個性化定製請求等。但願讀完本文,能對您有所幫助哦!
https://github.com/wg/wrk
https://zjumty.iteye.com/blog/2221040
http://www.cnblogs.com/xinzhao/p/6233009.html