一, 简介
wrk 是一款针对 Http 协议的基准测试工具, 它能够在单机多核 CPU 的条件下, 使用系统自带的高性能 I/O 机制, 如 epoll,kqueue 等, 通过多线程和事件模式, 对目标机器产生大量的负载.
优势:
轻量级性能测试工具
安装简单
学习曲线基本为 0, 几分钟就学会使用了
基于系统自带的高性能 I/O 机制, 如 epoll,kqueue, 利用异步的事件驱动框架, 通过很少的线程就可以压出很大的并发量
劣势:
wrk 目前仅支持单机压测, 后续也不太可能支持多机器对目标机压测, 因为它本身的定位, 并不是用来取代 JMeter, LoadRunner 等专业的测试工具.
二, 格式及用法
- Usage: wrk <options> <url>
- Options:
- -c, --connections <N> Connections to keep open
- -d, --duration <T> Duration of test
- -t, --threads <N> Number of threads to use
- -s, --script <S> Load Lua script file
- -H, --header <H> Add header to request
- --latency Print latency statistics
- --timeout <T> Socket/request timeout
- -v, --version Print version details
- Numeric arguments may include a SI unit (1k, 1M, 1G)
- Time arguments may include a time unit (2s, 2m, 2h)
翻译成中文:
使用方法: 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)
三, 简单压测及结果分析
做一个简单的压测, 分析下结果:
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 秒的压测, 并要求在压测结果中输出响应延迟信息.
以下是解释压测结果:
- 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)
四, 使用 lua 脚本进行压测
1,lua 声明周期
共有三个阶段, 启动阶段, 运行阶段, 结束阶段. wrk 支持在这三个阶段对压测进行个性化.
启动阶段
function setup(thread)
在脚本文件中实现 setup 方法, wrk 就会在测试线程已经初始化但还没有启动的时候调用该方法. wrk 会为每一个测试线程调用一次 setup 方法, 并传入代表测试线程的对象 thread 作为参数. setup 方法中可操作该 thread 对象, 获取信息, 存储信息, 甚至关闭该线程.
- thread.addr - get or set the thread's server address
- thread:get(name) - get the value of a global in the thread's env
- thread:set(name, value) - set the value of a global in the thread's env
- thread:stop() - stop the thread
运行阶段
function init(args) -- 由测试线程调用, 只会在进入运行阶段时, 调用一次. 支持从启动 wrk 的命令中, 获取命令行参数;
function delay() -- 在每次发送 request 之前调用, 如果需要 delay, 那么 delay 相应时间;
function request() -- 用来生成请求; 每一次请求都会调用该方法, 所以注意不要在该方法中做耗时的操作;
function response(status, headers, body) -- 在每次收到一个响应时调用; 为提升性能, 如果没有定义该方法, 那么 wrk 不会解析 headers 和 body;
结束阶段
function done(summary, latency, requests) -- 在整个测试过程中只会调用一次, 可从参数给定的对象中, 获取压测结果, 生成定制化的测试报告.
2, 自定义脚本中可访问的变量和方法:
变量: wrk
- wrk = {
- scheme = "http",
- host = "localhost",
- port = nil,
- method = "GET",
- path = "/",
- headers = {},
- body = nil,
- thread = <userdata>,
- }
方法: wrk.fomat wrk.lookup wrk.connect
function wrk.format(method, path, headers, body) -- 根据参数和全局变量 wrk, 生成一个 HTTP rquest string.
function wrk.lookup(host, service) -- 给定 host 和 service(port/well known service name), 返回所有可用的服务器地址信息.
function wrk.connect(addr) -- 测试与给定的服务器地址信息是否可以成功创建连接
3,lua 脚本压测实例
压测命令: wrk -t8 -c200 -d30s --latency -s test.lua http://www.bing.com
test.lua 是用 lua 写的压测脚本, 如下是压测脚本的实例:
使用 post 方法压测
- wrk.method = "POST"
- wrk.headers["S-COOKIE2"]="a=2&b=Input&c=10.0&d=20191114***"
- wrk.body = "recent_seven=20191127_32;20191128_111"
- wrk.headers["Host"]="api.shouji.**.com"
- function response(status,headers,body)
- if status ~= 200 then
- print(body)
- -- wrk.thread:stop()
- 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
wrk 读取文件, 实现随机 header-cookie
- idArr = {}
- falg = 0
- wrk.method = "POST"
- wrk.body = "a=1"
- function init(args)
- for line in io.lines("integral/cookies.txt") do
- print(line)
- idArr[falg] = line
- falg = falg+1
- end
- falg = 0
- end
- --wrk.method = "POST"
- --wrk.body = "a=1"
- --wrk.path = "/v1/points/reading"
- request = function()
parms = idArr[math.random(0,4)] 随机传递文件中的参数
--parms = idArr[falg%(table.getn(idArr)+1)] 循环传递文件中的参数
- wrk.headers["S-COOKIE2"] = parms
- falg = falg+1
- return wrk.format()
- end
wrk 创建数组并初始化, 拼接随机参数
- idArr = {};
- function init(args)
- idArr[1] = "1";
- idArr[2] = "2";
- idArr[3] = "3";
- idArr[4] = "4";
- end
- request = function()
- parms = idArr[math.random(1,4)]
- path = "/v1/points/reading?id="..parms
- return wrk.format("GET",path)
- end
来源: https://www.cnblogs.com/l199616j/p/12156600.html