wrk - 本地压测工具实操
说明: 利用 wrk 2 分钟知晓你新开发的接口的基本性能
一、简介
wrk 是一个开源的、热门的、现代的单机 HTTP 基准测试工具。
wrk 是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 epoll,kqueue 等,通过多线程和事件模式,对目标机器产生大量的负载。
PS: 其实,wrk 是复用了 redis 的 ae 异步事件驱动框架,准确来说 ae 事件驱动框架并不是 redis 发明的, 它来至于 Tcl 的解释器 jim, 这个小巧高效的框架, 因为被 redis 采用而被大家所熟知。
并且内置了一个可选的 Lua JIT 脚本执行引擎,可以处理复杂的 HTTP 请求生成、响应处理以及自定义压测报告。
二、跟其他压测工具优缺点对比
一些常用的性能测试工具,如 Apache ab, Apache JMeter (互联网公司用的较多),LoadRunner 等。
wrk 的优势:
* 轻量级性能测试工具;
wrk 的结果相比 ab 测试结果来说,多了一个延时直方图,有了这个直方图,我们可以更清晰的看到延迟的分布情况。这也是博主选择 wrk 最重要的原因
* 安装简单(相对 Apache ab 来说);
* 学习曲线基本为零,几分钟就能学会咋用了;
* 基于系统自带的高性能 I/O 机制,如 epoll, kqueue, 利用异步的事件驱动框架,通过很少的线程就可以压出很大的并发量;
劣势
wrk 目前仅支持单机压测,后续也不太可能支持多机器对目标机压测,因为它本身的定位,并不是用来取代 JMeter, LoadRunner 等专业的测试工具,wrk 提供的功能,对我们后端开发人员来说,应付日常接口性能验证还是比较友好的。
结论:应付日常接口性能验证还是比较友好的
三、Mac 上安装
先安装 Homebrew,安装方式参考官网 https://brew.sh
也可以执行下面命令 一键安装 > /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
安装 wrk: > brew install wrk
验证是否安装成功
> wrk -v
四、常用命令、注释和结果分析
命令: > wrk -t12 -c400 -d30s http://www.baidu.com
这条命令表示,利用 wrk 对 www.baidu.com 发起压力测试,线程数为 12,模拟 400 个并发请求,持续 30 秒。
详细参数含义解析
常用指令说明
-c, --connections: 要保持打开的 HTTP 连接的总数,每个线程处理数 N =连接/线程
-d, --duration: 测试持续时间, 如 2s, 2m, 2h
-t, --threads: 测试线程总数
-s, --script: 指定加载 lua 测试扩展脚本
-H, --header: 添加请求头信息, 如"User-Agent: wrk"
--latency: 打印延迟直方图信息
--timeout: 如果在此时间内没有收到响应,则记录超时.
-开头的指令为简写的,后面两个打印延迟直方图和超时设置没有简写的,只能--开头指定
命令行中输入 wrk --help, 可以看到支持以下子命令:
结果分析:
五、Get 请求如何进行压测
六、Post 请求如何进行压测
6.1、Post 请求
wrk 默认是采用 GET 请求方式进行接口测试,如果需要使用 POST 请求就需要使用到 lua 脚本,通过加载编写好的 lua 脚本来进行定制化的请求。采用-s 或者 --script 可以加载脚本文件。
wrk 的请求构造过程主要是针对每一个线程的,所以对于压测的环境也提供了一些函数方法来进行支持线程的环境定制化。
对于 POST 请求+入参不一致的解决:
对于这种需求,我们可以通过编写 Lua 脚本的方式,在运行压测命令时,通过参数 --script 来指定 Lua 脚本,来满足个性化需求。
wrk 对 Lua 脚本的支持
wrk 支持在三个阶段对压测进行个性化,分别是启动阶段、运行阶段和结束阶段。每个测试线程,都拥有独立的 Lua 运行环境。
动阶段
在脚本文件中实现 setup 方法,wrk 就会在测试线程已经初始化,但还没有启动的时候调用该方法。wrk 会为每一个测试线程调用一次 setup 方法,并传入代表测试线程的对象 thread 作为参数。setup 方法中可操作该 thread 对象,获取信息、存储信息、甚至关闭该线程。
运行阶段
* init(args): 由测试线程调用,只会在进入运行阶段时,调用一次。支持从启动 wrk 的命令中,获取命令行参数;
* delay(): 在每次发送请求之前调用,如果需要定制延迟时间,可以在这个方法中设置;
* request(): 用来生成请求, 每一次请求都会调用该方法,所以注意不要在该方法中做耗时的操作;
* response(status, headers, body): 在每次收到一个响应时被调用,为提升性能,如果没有定义该方法,那么 wrk 不会解析 headers 和 body;
结束阶段
done() 方法在整个测试过程中只会被调用一次,我们可以从给定的参数中,获取压测结果,生成定制化的测试报告。
6.2、lua 脚本
首先下载 lua 脚本 把接口+入参替换为对应值
暂时无法在{app_display_name}文档外展示此内容
然后控制台输入如下命令(需要修改 ip 地址)
七、小技巧
如何将某个参数变成随机参数
-- 动态生成每个请求的 url
local requestPath = string.gsub(wrk.path,"{appId}",math.random(1,10))
-- 返回请求的完整字符串:http://127.0.0.1//app/666/review_digress_list
return wrk.format(nil, requestPath)
命令行里打印日志
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))
八、注意事项
wrk 本身不是依赖线程数来模拟并发数的所以线程数量设置在核心数左右最好,线程数多了测试系统消耗大,可能带来反效果。之前测试跟核心数一致的线程数和两倍核心数的线程数,前者压出的 QPS 更高。
关于线程数,并不是设置的越大,压测效果越好,线程设置过大,反而会导致线程切换过于频繁,效果降低,一般来说,推荐设置成压测机器 CPU 核心数的 2 倍到 4 倍就行了。
版权声明: 本文为 InfoQ 作者【Monin】的原创文章。
原文链接:【http://xie.infoq.cn/article/b02cc267f66dcff99d13b259a】。文章转载请联系作者。
评论