wrk是一种现代HTTP基准测试工具,能够在单个多核CPU上运行时产生大量负载。它结合了多线程设计和可扩展的事件通知系统,如epoll和kqueue,以及使用了redis的'ae'事件循环,可以用很少的线程压出很大的并发量。
可以从github上下载wrk源码,如果没有git可以百度安装一下。
wrk是在服务器上执行的压测工具,所以需要在服务器上安装
1.window系统打开git窗口,在目录中使用此命令下载wrk(如果服务器中有git,则在服务器中使用此命令下载即可):
git clone https://github.com/wg/wrk.git wrk
2.把下载下来的wrk文件夹打个压缩包,打开连接linux服务器的工具(如Xshell),在服务器上创建一个存放wrk文件和测试用的文件的文件夹
3.进入创建的文件夹后使用rz 命令上传wrk压缩包,然后解压
4.解压后,进入wrk文件夹,使用make命令编译
cd wrk
make
5.编译成功后,会在项目路径下生成可执行文件wrk,随后就可以使用了。也可以拷贝到/usr/local/bin,这样就可以在任何路径直接使用wrk了。
ln -s /xxx/xxx/wrk /usr/local/bin
6.输入wrk,如果有以下显示,则说明安装成功了
1、最简单的压力测试示例,get请求,固定url固定参数
wrk -t10 -c30 -d 2s -T5s --latency http://www.baidu.com
注意:我这里试的粘贴过去会有问题,建议手敲一下
参数释义:
-t:需要模拟的线程数
-c:需要模拟的连接数
-d:测试的持续时间
----timeout 或 -T:超时的时间
--latency:显示延迟统计
-s 或 --script: lua脚本,使用方法往下看
-H, --header: 添加http header, 比如. "User-Agent: wrk"
测试结果:
测试结果解析:
Running 2s test @ http://www.baidu.com
10 threads and 30 connections平均值 标准差 最大值 正负一个标准差占比
线程状态 Thread Stats Avg Stdev Max +/- Stdev
响应时间 Latency 168.45ms 265.72ms 1.48s 87.68%
每线程每秒完成请求数Req/Sec 25.78 26.22 120.00 86.55%
Latency Distribution 延迟统计
50% 31.15ms 有50%的请求执行时间是在31.15ms内完成
75% 243.14ms 有75%的请求执行时间是在243.14ms内完成
90% 479.94ms 有90%的请求执行时间是在479.94内完成
99% 1.31s 有99%的请求执行时间是在1.31s内完成
365 requests in 2.01s, 5.55MB read 2秒执行了365个请求,读了5.55MB数据Socket errors: connect 29, read 2, write 0, timeout 0 错误 : 连接错误:29 读错误:2
Requests/sec: 182.02 每秒请求数(也就是QPS)
Transfer/sec: 2.77MB 每秒钟读取2.77兆数据量
复杂一些的一些则需要用到lua脚本
lua脚本学习可看此地址 http://www.runoob.com/lua/lua-tutorial.html
执行命令为 wrk -t5 -c10 -d 1s -T5s --latency -s test1.lua http://www.baidu.com
-s test1.lua 则是执行lua脚本
2.wrk发post请求
执行命令为 wrk -t5 -c10 -d 1s -T5s --latency -s test1.lua http://172.18.11.11/queryUserByName
lua脚本为:body中是参数 ,headers一般不用传,看个人需要
request = function()
headers = {Connection= "keep-alive"}
body = "name=中文"
return wrk.format("POST",path,headers,body)
end
3.wrk发送随机参数-(get)
执行命令为 wrk -t5 -c10 -d 1s -T5s --latency -s test1.lua http://www.baidu.com
request = function() num = math.random(1000,9999) path = "/test.html?t=" .. num return wrk.format("GET", path) end
path这个字符串会拼到 http://www.baidu.com 后
wrk.format这个方法简介:
根据参数和全局变量wrk生成一个http请求
函数签名: function wrk.format(method, path, headers, body)
method:http方法,比如GET/POST等
path: url上的路径(含参数) 如 /index, /index?name=xiaoming&id=123
headers: http header(请求头)
body: http body(参数)
4.wrk从文件中依次选择参数
适用于用多条固定的参数测试
先在执行脚本同级目录下创建一个文件,例如:ids.txt
文件内容为:
1
2
3
执行命令为 wrk -t5 -c10 -d 1s -T5s --latency -s test1.lua http://www.baidu.com
lua脚本文件内容为:
idArr = {} falg = 0 function init(args) for line in io.lines("ids.txt") do print(line) idArr[falg] = line falg = falg + 1 end falg = 0 end request = function() local path ="/getInfo?id=%s" parms = idArr[falg%(table.getn(idArr) + 1)] path = string.format(path,parms) falg = falg + 1 return wrk.format(nil, path) end
会把取到的值拼到 http://www.baidu.com后
其中
for line in io.lines("ids.txt") do //io.lines()是从ids.txt中取一行数据
print(line)
idArr[falg] = line
falg = falg + 1
end
table.getn()是获取集合的长度
wrk.format()方法上面有介绍
5.wrk传中文:
如果要传的参数中有中文,则需要转码,lua脚本如下:
需要加入encodeParm()方法,中文参数调用其转码
idArr = {}
falg = 0
function init(args)
for line in io.lines("ids.txt") do
print(line)
idArr[falg] = line
falg = falg + 1
end
falg = 0
endfunction encodeParm(s)
s = string.gsub(s,"([^%w%.%-])",function(c) return string.format("%%%02X",string.byte(c))end)
print(string.gsub(s," ","+"))
return string.gsub(s," ","+")
endrequest = function()
local path ="/user/identitySelect?name=%s"
parms = idArr[falg%(table.getn(idArr) + 1)]
parms = encodeURL(parms)
path = string.format(path,parms)
--path = encodeParm(path)
falg =falg + 1
print("path",path)
return wrk.format(nil, path)
end
6.发送多个请求
执行命令为 wrk -t5 -c10 -d 1s -T5s --latency -s test5.lua http://www.baidu.com
lua脚本为:
init = function(args)
local r = {}
r[1] = wrk.format(nil, "/info/getInfoById?id=100001&channel=0")
r[2] = wrk.format(nil, "/info/getByName?name=aaa&startindex=0&length=10")
r[3] = wrk.format(nil, "/info/getByUserId?id=88888888")req = table.concat(r)
endrequest = function()
return req
end
7.lua声明周期
共有三个阶段,启动阶段,运行阶段,结束阶段
启动阶段:
function setup(thread) :
wrk会在线程初始化但还没有启动的时候调用setup(thread)方法。且每个线程都会调用一次,并传入测试线程的对象thread作为参数。
thread.addr 设置请求需要打到的ip
thread:get(name) 获取线程全局变量
thread:set(name, value) 设置线程全局变量
thread:stop() 终止线程
运行阶段:
function init(args) -- 每个线程都会先调用1次,其中可以做一些初始化工作,比如读测试数据
function delay() -- 每次请求调用1次,发送下一个请求之前的延迟, 单位为ms
function request() -- 每次请求调用1次,返回http请求
function response(status, headers, body) -- 每次请求调用1次,返回http响应
如有不当之处,还望指出!