一.安装
绝大部分Unix系统都支持wrk,需要OS支持lua & openSSL.(Linux都支持)
CentOS 7安装

  1. 安装Git
    yum install -y git
    如果已安装跳到下一步.
  2. 下载wrk源码
    git clone https://github.com/wg/wrk.git wrk
    如果遇到github网络较差,使用国内镜像
    git clone https://gitee.com/mirrors/wrk.git wrk
  3. 进行目录
    cd wrk
  4. 安装gcc
    yum -y install gcc
  5. 编译
    wrkC/C++写的,需要安装到本地
    make
    完成后当前目录下会有wrk
  6. 软连接
    ln -s ~/wrk/wrk /usr/local/bin

    如遇到编译错误:fatalerror:openssl/ssl.h:Nosuchfile or directory
    yum -y install openssl-devel
    (Ubuntu中 apt-get install -y openssl-devel)

二.wrk
1.执行wrk
wrk安装及lua脚本进行API性能测试_第1张图片
2.参数说明
-c 和服务器保持的TCP连接数
-d 压测时间
-t 使用多少个线程压测
-s 指定Lua脚本位置
-H 为每个http请求增加http请求头
--latency 压测结束后统计延时信息
--timeout 设置超时时间
wrk使用异步非阻塞IO,并非使用线程去模拟并发连接,所以线程一般设置为cpu核数即可
-c的参数必须大于等于-t的参数值.但也不要太大,可能导致too many open files error.
查看系统的配置
cat /proc/sys/fs/file-max
3.wrk示例
wrk -t4 -c100 -d30s --latency https://www.baidu.com
使用4个线程来模拟100个并发,整个压测持续30s.

wrk -t4 -c2000 -d60s -T5s -script=post.lua --latency http://localhost/api/user/login
模拟4个线程,2000个连接,在60秒内,设置超时时间为5秒执行post.lua脚本中请求.

统计结果分析

[web@localhost ~]$ wrk -t4 -c10 -d10s -T3s --latency http://www.abc.cn
Running 10s test @ http://www.abc.cn
  4 threads and 10 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    19.16ms   12.69ms 237.07ms   99.18%
    Req/Sec   109.24     11.49   121.00     89.50%
  Latency Distribution
     50%   17.95ms
     75%   18.43ms
     90%   19.35ms
     99%   29.69ms
  4372 requests in 10.05s, 1.59MB read
Requests/sec:    434.84
Transfer/sec:    161.79KB

第五行是延迟统计:平均延迟,标准差,最大延迟,正负一个标准差的占比
第六行是线程请求次数统计:每个线程的平均请求次数,标准差,最大请求次数,正负一个标准差的结果占比
第八到十一行是延迟分布统计:50%的请求延迟在多少以内,75%的,90%的,99%的
第十二行是总请求数


AVG 平均值 每次测试的平均值
StDEV 标准偏差 结果的离散程序,越高说明越不稳定
MAX 最大值 最大的一次结果
+/- Stdev 正负一个标准差占比 结果的离散程序 ,越大越不稳定
Latency:可以理解为响应时间
Req/Sec: 每个线程每秒钟完成的请求数

一般来说我们主要关注平均值和最大值.标准差如果太大说明样本本身离散程度比较高,有可能系统性能波动很大.
总共完成请求数5037.
5037 requestions 30.95s,75.28MB read
Socketerrors:connect 0,read 5,write 0,timeout 4000
出现socketerrors说明该地址有错误
Requests/sec: 168.5
Transfer/sec:2.50M
每秒请求数据和每秒数据传输量.
4.wrk的生命周期
对于一些动态构建的请求,如 认证,校验,http请求参数化等,可以使用lua脚本复写wrk中的hook函数.
调用lua分为下面三个阶段:setup,running,done.
wrk安装及lua脚本进行API性能测试_第2张图片

    每个阶段作用:
    setup:线程初始后会调用一次,每个线程只调用一次.
    init: 每次请求发送之前被调用,可以接受wrk命令行额外参数
    delay:每个函数返回一个数值,在这次请求执行完成后延迟多长时间可以进行下一个请求,对应thinking time场景
    request:通过这个函数可以每次请求之前修改本次请求体和Header,这是常用的函数,一般在这里写要压测的业务逻辑
    response:每次请求返回后可以针对响应内容做特殊处理,例如遇到特殊情况停止测试或输出到控制台上
    done:可以用于自定义结果报表,整个过程中只执行一次.

5.wrk的全局属性

        wrk ={
                scheme ="http",
                host="localhost",
                port=nil,
                method="GET",
                path="/",
                headers={},
                body=nil,
                thread=,
        }

6.wrk的全局方法

--生成整个reqeust的string
function wrk.format(method,path,headers,body)
--获取域名ip和port,返回table,如'{127.0.0.1:8080}'
function wrk.lookup(host,service)
--判断addr是否能连接,返回true/false
function wrk.connect(addr)

setup 阶段:线程创建之后,启动之前

 function setup(thread)
 --thread提供一个属性,3个方法
 --thread.addr设置请求需要打到的ip
 --thread:get(name)获取线程全局变量
 --thread.set(name,value)设置线程全局变量
 --thread:stop()终止线程

Running阶段

 function init(args)
 --每个线程仅调用一次,args用于获取命令行中传入的参数,如--env=pre
 function delay()
 --每个线程调用多次,发送下一个请求之前的延迟,单位为ms
 function request()
 --每个线程调用多次,返回http请求
 function response(status,headers,body)
 --每个线程调用多次,返回http响应

Done阶段:可用于自定义结果报表,整个过程只执行一次.

 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编写脚本
使用lua脚本编写GET/POST API测试
`urimap = {
"/api/login/authenticationUser",
"/api/enquiry/list",
"/api/enquiry/technical/list",
"/api/technical/enquiry/list/",
"/api/taskorder/history/list",
}
methodmap = {
"POST",
"GET",
"GET",
"GET",
"GET",
}
--双括号里面不转义
params = {
"loginname=fuwushang&password=123456",
"pageNo=1&pageSize=5",
"",
"pageNo=1&pageSize=5",
"pageNo=1&pageSize=5&taskOrderId=f3e2d93a489542b88cc09e6462c3268b",
}
math.randomseed(os.time())
setup=function()

end
init = function()
local r = {}
local path = "" --局部变量(不加local是全局变量)
local method = "get" --default get
--header
wrk.headers["Hash"] = "hashcode"
wrk.headers["Token"] = "uuidtoken"

for k, v in pairs(urimap) do --k 从1开始,非0
    path = v --path
    method = methodmap[k] --method

    if method == "POST" then
        wrk.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
        wrk.headers["User-Agent"] = "wrk"
        wrk.headers["Connection"] = "keep-alive"
        wrk.body = params[k]
    end

    if method == "GET" and params[k] ~= "" then
        wrk.headers["Authorization1"] = "Bearer  0deca37bc1ed4a4487c6a7fbb186d9e5"
        wrk.headers["User-Agent"] = "wrk"
        wrk.headers["Connection"] = "keep-alive"
        path = v .. "?" .. params[k]
    end
    io.write(method, "---", params[k], "---", path, "\n") -- 打印请求方式(1个线程会打印一次),参数,路径(不含域名)
    r[k] = wrk.format(method, path)
end
req = table.concat(r)

end

request = function()
return req
end

response = function(status, headers, body)
if status ~= 200 then
print("status:", status)
print("error:", body)
wrk.thread:stop()
else
print("body:", body)
end
end

done = function(sumarry, latency, requests)
local durations = sumarry.duration / 1000000 --执行时间,单位是秒
local errors = sumarry.errors.status --http status不是200,300开头的
local requests = sumarry.requests --总请求数
local valid = requests - errors --有效请求数=总请求数-error请求数

io.write("Durations:    " .. string.format("%.2f", durations) .. "s" .. "\n")
io.write("Requests:     " .. sumarry.requests .. "\n")
io.write("Avg RT:          " .. string.format("%.2f", latency.mean / 1000) .. "ms" .. "\n")
io.write("Max RT:          " .. (latency.max / 1000) .. "ms" .. "\n")
io.write("Min RT:          " .. (latency.min / 1000) .. "ms" .. "\n")
io.write("Error requests:  " .. errors .. "\n")
io.write("Valid requests:  " .. valid .. "\n")
io.write("QPS:             " .. string.format("%.2f", valid / durations) .. "\n")
io.write("--------------------------\n")

end
`
四.wrk命令测试
wrk -t4 -c100 -d20s -s apiPressTest.lua --latency http://192.168.1.202/