性能测试工具——wrk

79

介绍

wrk 是一款简单的 HTTP 压测工具。最大的优点就是能使用很少的线程压出很大的并发量,原因是它使用了一些操作系统特定的高性能 IO 机制,比如 select,epoll 等,其实它是复用了 Redis 的 ae 异步事件。

GitHub 地址:https://github.com/wg/wrk

安装

git clone https://github.com/wg/wrk.git
cd wrk
make

编译出的可执行程序 wrk 就在 Makefile 文件所在目录。链接或者添加一下环境变量,就能随时使用这个工具了。

简单使用

michaelliu@C02ZRD0ZMD6N ~ % wrk -t4 -c2500 -d20 "https://www.baidu.com"
Running 20s test @ https://www.baidu.com
  4 threads and 2500 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   518.51ms  387.16ms   2.00s    71.39%
    Req/Sec    85.09     33.16   202.00     63.53%
  6708 requests in 20.07s, 101.78MB read
  Socket errors: connect 2254, read 0, write 0, timeout 357
Requests/sec:    334.31
Transfer/sec:      5.07MB

其中,
-t 代表需要模拟的线程数
-c 代表需要模拟的连接数
-d 代表测试的持续时间
-timeout 超时时间
-latency 显示延迟时间

搭配 Lua 脚本使用

在基本压测中,每次发送的请求都是一样的,很多时候我们压测的请求体是每个请求都不一样,这时候就要写 lua 脚本来压测。

login.lua:

#!/usr/local/bin/lua

wrk.path = "/api/login"

-- user_name password list:
account_list = {
   '{"user_name": "YIkQ3SIs0", "password": "Sttv5ZNYLx"}',
   '{"user_name": "wARAaC6vzeUM0f", "password": "OLefD"}',
   '{"user_name": "TDIJy5MghU1w", "password": "XESjfruKP"}',
}

local counter = 1
local threads = {}

function setup(thread)
   thread:set("id", counter)
   table.insert(threads, thread)
   counter = counter + 1
end

function init(args)
   requests  = 0
   responses = 0

   local msg = "thread %d created"
   print(msg:format(id))
end

function request()
   local headers = { }
   headers['Content-Type'] = "application/json"
   wrk.body = account_list[math.random(1, 200)]
   
   requests = requests + 1

   return wrk.format('POST', path, headers)
end

function response(status, headers, body)
    if status ~= 200 then
        print(status)
    end
    responses = responses + 1
end

-- 获取cookie
function getCookie(cookies, name)  
    local start = string.find(cookies, name .. "=")  
    if start == nil then  
       return nil  
    end  
    return string.sub(cookies, start + #name + 1, string.find(cookies, ";", start) - 1)  
end

-- 统计信息
function done(summary, latency, requests)
   for index, thread in ipairs(threads) do
      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))
   end
end

使用 -s 参数,添加 lua 脚本即可:

michaelliu@C02ZRD0ZMD6N lua % wrk -t 16 -c 200 -d 20s --latency -s login.lua http://localhost:8080
Running 20s test @ http://localhost:8080
  16 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    23.19ms   43.21ms 496.29ms   96.93%
    Req/Sec   711.56    146.29     0.90k    90.01%
  Latency Distribution
     50%   15.98ms
     75%   19.22ms
     90%   23.26ms
     99%  290.49ms
  220146 requests in 20.06s, 93.24MB read
Requests/sec:  10976.13
Transfer/sec:      4.65MB

所以上面参数的意思就是 16 个线程,200 个连接,持续 20s,使用脚本 login.lua ,可以看到 Requests/sec 就是 QPS 是 10976.13。