HTTP性能測試工具wrk安裝及使用
wrk 是一個很簡單的 http 性能測試工具,沒有Load Runner那麽復雜,他和 apache benchmark(ab)同屬於HTTP性能測試工具,但是比 ab 功能更加強大,並且可以支持lua腳本來創建復雜的測試場景。
wrk 的一個很好的特性就是能用很少的線程壓出很大的並發量,原因是它使用了一些操作系統特定的高性能 io 機制, 比如 select, epoll, kqueue 等.
其實它是復用了 redis 的 ae 異步事件驅動框架. 確切的說 ae 事件驅動框架並不是 redis 發明的, 它來至於 Tcl的解釋器 jim, 這個小巧高效的框架, 因為被 redis 采用而更多的被大家所熟知。
wrk 是開源的, 代碼在 github 上. https://github.com/wg/wrk
安裝
wrk 支持大多數類 UNIX 系統,不支持 windows。需要操作系統支持LuaJIT 和 OpenSSL,不過不用擔心,大多數類 Unix 系統都支持。安裝 wrk 非常簡單,只要從 github 上下載 wrk 源碼,在項目路徑下執行 make 命令即可。
Unbuntu/Debian下的安裝
sudo apt-get install build-essential libssl-dev git -y git clone https://github.com/wg/wrk.git wrk cd wrk make # 把生成的wrk移到一個PATH目錄下面, 比如 sudo cp wrk /usr/local/bin
CentOs/RedHat/Fedora 下的安裝
sudo yum groupinstall ‘Development Tools‘
sudo yum install openssl-devel
sudo yum install git
git clone https://github.com/wg/wrk.git wrk
cd wrk
make
# 把生成的 wrk 移到一個 PATH 目錄下面, 比如
sudo cp wrk /usr/local/bin
mac 下快捷安裝
brew install wrk
基本使用
wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html
使用 12 個線程運行 30 秒, 400 個 http 並發
命令行選項
使用方法: 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)
做一次簡單壓測,分析下結果
wrk -t8 -c200 -d30s --latency "http://www.bing.com"
輸出:
Running 30s test @ http://www.bing.com
8 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 46.67ms 215.38ms 1.67s 95.59%
Req/Sec 7.91k 1.15k 10.26k 70.77%
Latency Distribution
50% 2.93ms
75% 3.78ms
90% 4.73ms
99% 1.35s
1790465 requests in 30.01s, 684.08MB read
Requests/sec: 59658.29
Transfer/sec: 22.79MB
以上使用 8 個線程 200 個連接,對 bing 首頁進行了 30 秒的壓測,並要求在壓測結果中輸出響應延遲信息。以下對壓測結果進行簡單註釋:
Running 30s test @ http://www.bing.com (壓測時間30s)
8 threads and 200 connections (共8個測試線程,200個連接)
Thread Stats Avg Stdev Max +/- Stdev
(平均值) (標準差)(最大值)(正負一個標準差所占比例)
Latency 46.67ms 215.38ms 1.67s 95.59%
(延遲)
Req/Sec 7.91k 1.15k 10.26k 70.77%
(處理中的請求數)
Latency Distribution (延遲分布)
50% 2.93ms
75% 3.78ms
90% 4.73ms
99% 1.35s (99分位的延遲)
1790465 requests in 30.01s, 684.08MB read (30.01秒內共處理完成了1790465個請求,讀取了684.08MB數據)
Requests/sec: 59658.29 (平均每秒處理完成59658.29個請求)
Transfer/sec: 22.79MB (平均每秒讀取數據22.79MB)
可以看到,wrk 使用方便,結果清晰。並且因為非阻塞 IO 的使用,可以在普通的測試機上創建出大量的連接,從而達到較好的壓測效果。
lua腳本壓測
在基本壓測中, 每次發送的請求都是一樣的,很多時候我們壓測的請求體是每個請求都不一樣, 這時候就要寫lua基本來壓測
使用 POST 方法壓測
wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
wrk -t2 -d30s -c1k -s xxx.lua http://192.168.17.1/
每個 request 的參數都不一樣
request = function()
uid = math.random(1, 10000000)
path = "/test?uid=" .. uid
return wrk.format(nil, path)
end
解釋一下 wrk.format 這個函數
wrk.format 這個函數的作用,根據參數和全局變量 wrk 生成一個 http 請求
函數簽名: function wrk.format(method, path, headers, body)
method:http方法,比如GET/POST等
path: url上的路徑(含函數)
headers: http header
body: http body
每個線程先登錄然後壓測
token = nil
path = "/authenticate"
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 = "/resource"
wrk.headers["X-Token"] = token
end
end
發送 json
request = function()
local headers = { }
headers[‘Content-Type‘] = "application/json"
body = {
mobile={"1533899828"},
params={code=math.random(1000,9999)}
}
local cjson = require("cjson")
body_str = cjson.encode(body)
return wrk.format(‘POST‘, nil, headers, body_str)
end
若運行的時候報錯找不到cjson, 可以安裝 luarocks install lua-cjson
wrk lua腳本說明
wrk 壓測腳本有3個生命周期, 分別是 啟動階段,運行階段和結束階段,每個線程都有自己的lua運行環境
啟動階段
function setup(thread)
在腳本文件中實現setup方法,wrk就會在測試線程已經初始化但還沒有啟動的時候調用該方法。wrk會為每一個測試線程調用一次setup方法,並傳入代表測試線程的對象thread作為參數。setup方法中可操作該thread對象,獲取信息、存儲信息、甚至關閉該線程。
-- thread提供了1個屬性,3個方法
-- thread.addr 設置請求需要打到的ip
-- thread:get(name) 獲取線程全局變量
-- thread:set(name, value) 設置線程全局變量
-- thread:stop() 終止線程
運行階段
function init(args)
-- 每個線程僅調用1次,args 用於獲取命令行中傳入的參數, 例如 --env=pre
function delay()
-- 每次請求調用1次,發送下一個請求之前的延遲, 單位為ms
function request()
-- 每次請求調用1次,返回http請求
function response(status, headers, body)
-- 每次請求調用1次,返回 http 響應
init由測試線程調用,只會在進入運行階段時,調用一次。支持從啟動wrk的命令中,獲取命令行參數; delay在每次發送request之前調用,如果需要delay,那麽delay相應時間; request用來生成請求;每一次請求都會調用該方法,所以註意不要在該方法中做耗時的操作; reponse在每次收到一個響應時調用;為提升性能,如果沒有定義該方法,那麽wrk不會解析headers和body; 結束階段
結束階段
function done(summary, latency, requests)
latency.min -- minimum value seen
latency.max -- maximum value seen
latency.mean -- average value seen
latency.stdev -- standard deviation
latency:percentile(99.0) -- 99th percentile value
latency(i) -- raw value and count
summary = {
duration = N, -- run duration in microseconds
requests = N, -- total completed requests
bytes = N, -- total bytes received
errors = {
connect = N, -- total socket connection errors
read = N, -- total socket read errors
write = N, -- total socket write errors
status = N, -- total HTTP status codes > 399
timeout = N -- total request timeouts
}
}
該方法在整個測試過程中只會調用一次,可從參數給定的對象中,獲取壓測結果,生成定制化的測試報告。
線程變量
wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = <userdata>,
}
-- 生成整個request的string,例如:返回
-- GET / HTTP/1.1
-- Host: tool.lu
function wrk.format(method, path, headers, body)
-- method: http方法, 如GET/POST/DELETE 等
-- path: url的路徑, 如 /index, /index?a=b&c=d
-- headers: 一個header的table
-- body: 一個http body, 字符串類型
-- 獲取域名的IP和端口,返回table,例如:返回 `{127.0.0.1:80}`
function wrk.lookup(host, service)
-- host:一個主機名或者地址串(IPv4的點分十進制串或者IPv6的16進制串)
-- service:服務名可以是十進制的端口號,也可以是已定義的服務名稱,如ftp、http等
-- 判斷addr是否能連接,例如:`127.0.0.1:80`,返回 true 或 false
function wrk.connect(addr)
原文轉載自: https://www.ruoxiaozh.com/blog/article/84
HTTP性能測試工具wrk安裝及使用