wrk 是一個很簡單的 http 性能測試工具,沒有Load Runner那麼複雜,他和 apache benchmark(ab)同屬於HTTP性能測試工具,可是比 ab 功能更增強大,而且能夠支持lua腳原本建立複雜的測試場景。html
wrk 的一個很好的特性就是能用不多的線程壓出很大的併發量,緣由是它使用了一些操做系統特定的高性能 io 機制, 好比 select, epoll, kqueue 等.git
其實它是複用了 redis 的 ae 異步事件驅動框架. 確切的說 ae 事件驅動框架並非 redis 發明的, 它來至於 Tcl的解釋器 jim, 這個小巧高效的框架, 由於被 redis 採用而更多的被你們所熟知。github
wrk 是開源的, 代碼在 github 上. https://github.com/wg/wrkredis
wrk 支持大多數類 UNIX 系統,不支持 windows。須要操做系統支持LuaJIT 和 OpenSSL,不過不用擔憂,大多數類 Unix 系統都支持。安裝 wrk 很是簡單,只要從 github 上下載 wrk 源碼,在項目路徑下執行 make 命令便可。shell
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
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
brew install wrk
wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html
使用 12 個線程運行 30 秒, 400 個 http 併發apache
使用方法: 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)
作一次簡單壓測,分析下結果json
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 秒的壓測,並要求在壓測結果中輸出響應延遲信息。如下對壓測結果進行簡單註釋:windows
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 的使用,能夠在普通的測試機上建立出大量的鏈接,從而達到較好的壓測效果。centos
在基本壓測中, 每次發送的請求都是同樣的,不少時候咱們壓測的請求體是每一個請求都不同, 這時候就要寫lua基原本壓測服務器
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 = 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
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 壓測腳本有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