性能测试神器 wrk 使用教程
原文连接:https://blog.fengjx.com/wrk/
wrk 是一个类似 ab(apache bench)、jmeter 的压力测试工具,底层基于 epoll 和 kqueue 实现,能充分利用 cpu 资源,降低测试工具本身性能开销对测试结果准确性的影响。支持使用 lua 脚本自定义测试逻辑,使用上非常简单,但功能足够强大。
没有了解过 lua 的同学,可以看下 lua 简明教程 https://coolshell.cn/articles/10739.html
安装
- linux https://github.com/wg/wrk/wiki/Installing-wrk-on-Linux
- macOS https://github.com/wg/wrk/wiki/Installing-wrk-on-Mac-OS-X
- windows( Windows Subsystem for Linux ) https://github.com/wg/wrk/wiki/Installing-wrk-on-Windows-10
用法
$ wrk -h wrk: invalid option -- h 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
参数 | 说明 |
---|---|
-c | 与服务器保持的 http 连接数 |
-d | 压测时间 |
-t | 使用线程数 |
-s | 自定义 lua 脚本路径 |
-H | 自定义 http header 请求头,例如:"User-Agent: benchmark-wrk" |
--latency | 打印延迟统计数据 |
--timeout | http 超时时间 |
--version | 打印版本信息 |
eg: wrk -t2 -c5 -d10s https://httpbin.org/get
这种情况只适用于每次请求都相同的情况
$ wrk -t2 -c5 -d10s https://httpbin.org/get Running 10s test @ https://httpbin.org/get 2 threads and 5 connections Thread Stats Avg Stdev Max +/- Stdev Latency 251.97ms 50.38ms 510.96ms 94.52% Req/Sec 7.60 2.40 10.00 75.23% 146 requests in 10.05s, 61.17KB read Requests/sec: 14.52 Transfer/sec: 6.08KB
编写 lua 测试脚本
官方文档:https://github.com/wg/wrk/blob/master/SCRIPTING
编写 lua 脚本可以实现复杂的测试场景,例如:需要登录认证的接口,查询不用 id 的数据(相同 id 服务端可能有缓存,达不到真实压测效果)
先看官方一个简单的自定义脚本
wrk.method = "POST" wrk.body = "foo=bar&baz=quux" wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
$ wrk -d3s -c2 -s scripts/post.lua https://httpbin.org/get
wrk 是一个内置的全局 table 类型变量,不需要定义可以直接使用,修改 wrk 变量的值,会对所有请求都生效。
wrk = { scheme = "http", host = "localhost", port = nil, method = "GET", path = "/", headers = {}, body = nil, thread = <userdata> }
wrk 内置函数
-
wrk.format
function wrk.format(method, path, headers, body)
wrk.format returns a HTTP request string containing the passed parameters merged with values from the wrk table.
返回一个 http 请求字符串,参数会覆盖 wrk 全局配置,可以通过 format 可以构造出不同的 request
-
wrk.lookup
function wrk.lookup(host, service)
wrk.lookup returns a table containing all known addresses for the host and service pair. This corresponds to the POSIX getaddrinfo() function.
返回所有可用服务器的地址信息
-
wrk.connect
function wrk.connect(addr)
wrk.connect returns true if the address can be connected to, otherwise it returns false. The address must be one returned from wrk.lookup().
测试指定的服务器地址是否能正常连接
参考:
local addrs = nil function setup(thread) if not addrs then addrs = wrk.lookup(wrk.host, wrk.port or "http") for i = #addrs, 1, -1 do if not wrk.connect(addrs[i]) then table.remove(addrs, i) end end end thread.addr = addrs[math.random(#addrs)] end function init(args) local msg = "thread addr: %s" print(msg:format(wrk.thread.addr)) end
生命周期回调函数
wrk 包括下面几个生命周期,在脚本中重新定义这些全局函数,可以修改 wrk 默认行为,实现个性化测试需求。
The following globals are optional, and if defined must be functions:
global setup -- called during thread setup global init -- called when the thread is starting, global delay -- called to get the request delay, global request -- called to generate the HTTP request, global response -- called with HTTP response data, global done -- called with results of run
启动阶段
-
setup 每个线程初始化时执行一次
function setup(thread)
setup 方法会传入一个 thread 对象,可以修改或设置 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,终止线程
执行阶段
-
init 每个线程开始启动时执行一次
function init(args)
args 是通过命令行传入的参数,通过
--
指定例如:
wrk -d3s -c2 -s wrk.lua https://httpbin.org/get -- test 100
function init(args) for i, v in ipairs(args) do print(i,v) end end -- 输出 -- 1 test -- 2 100
-
delay 每次发送请求时,间隔时间(ms),每次请求执行一次
function delay()
返回值决定每次请求间隔
-
request 创建 request 时(发送 request 前)执行,每次请求执行一次
function request()
一般在这里会配合
wrk.format
方法,动态创建请求,这里不要执行耗时的代码,否则会影响测试结果准确性 -
response http 响应时执行,每次请求执行一次
function response(status, headers, body)
http 响应处理逻辑,参数对应 http 响应的
status
,headers
,body
。解析 header 和 body 的开销比较大,如果脚本没有定义
response
方法,wrk 将不会解析 header 和 body,这样测试结果会更加准确(解析响应数据是客户端负责的,不能算到服务器处理时间里面)
结束阶段
-
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 } }
官方示例
https://github.com/wg/wrk/blob/master/scripts/setup.lua
local counter = 1 local threads = {} function setup(thread) thread:set("id", counter) table.insert(threads, thread) counter = counter + 1 end function init(args) requests = 0 responses = 0 local msg = "thread %d created" print(msg:format(id)) end function request() requests = requests + 1 return wrk.request() end function response(status, headers, body) responses = responses + 1 end function done(summary, latency, requests) for index, thread in ipairs(threads) do 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)) end end
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
物联网开发服务批量绑定设备操作步骤图文解析
云栖号快速入门:【点击查看更多云产品快速入门】不知道怎么入门?这里分分钟解决新手入门等基础问题,可快速完成产品配置操作! 应用发布以后,可以为数据源是设备的组件批量绑定设备。新增绑定设备后,系统将生成一个可以单独使用的应用实例。适用于单独交付应用实例的场景。 前提条件 应用已发布。 应用中有组件的数据源是设备上报属性或事件。 背景信息 该功能适用于: 应用和设备并行研发的场景。 批量分发、拷贝应用设置的场景。 操作步骤 1.在应用编辑页左侧导航栏,单击设备绑定管理图标。2.在应用绑定设备页,单击新建设备配置。 3.在新建配置页,单击批量配置设备。4.在批量绑定设备对话框中,单击导出当前配置,下载当前配置文件。 5.打开已下载的配置文件Excel表,在Device Name列下,填入您要绑定的设备名称,并保存。 6.在批量绑定设备对话框中,单击下一步。7.单击导入,导入已编辑好的配置文件。8.在新建配置页底部,设置配置名称,单击发布配置。 执行结果 设备配置发布后,将生成一个应用实例。系统生成的应用地址,由于安全限制原因,有效期为24小时。已绑定您自己的域名的应用地址不受此限制,长期有效...
- 下一篇
从JIT到类加载再到实现原理解式Lambda编译慢的问题
问题回顾 描述的话不多说,直接上图: 看到输出结果了吗?为什么第一次和第二次的时间相差如此之多?咱们一起琢磨琢磨,也可以先去看看结论再回过头看分析 注:并非仅第二次快,而是除了第一次,之后的每一次都很快 给与猜想 是否和操作系统预热有关? 是否和JIT(即时编译)有关? 是否和ClassLoader类加载有关? 是否和Lambda有关,并非foreach的问题 验证猜想 操作系统预热 操作系统预热这个概念是我咨询一位大佬得到的结论,在百度 / Google 中并未搜索到相应的词汇,但是在模拟测试中,我用 普通遍历 的方式进行测试: 基本上每次都是前几次速度较慢,后面的速度更快,因此 可能 有这个因素影响,但差距并不会很大,因此该结论并不能作为问题的答案。 JIT 即时编译 首先介绍一下什么是JIT即时编译: 当 JVM 的初始化完成后,类在调用执行过程中,执行引擎会把字节码转为机器码,然后在操作系统中才能执行。在字节码转换为机器码的过程中,虚拟机中还存在着一道编译,那就是即时编译。 最初,JVM 中的字节码是由解释器( Interpreter )完成编译的,当虚拟机发现某个方法或代码块...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Hadoop3单机部署,实现最简伪集群