HTTP性能測試工具wrk安裝及使用

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

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 併發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腳本壓測

在基本壓測中, 每次發送的請求都是同樣的,不少時候咱們壓測的請求體是每一個請求都不同, 這時候就要寫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運行環境

image

啓動階段
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

相關文章
相關標籤/搜索