一.安装 绝大部分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 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. 每个阶段作用: 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=<userdata>, } 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/