wrk

brew install wrk
git clone https://github.com/wg/wrk
make
make WITH_LUAJIT=/usr WITH_OPENSSL=/usr

Usage: wrk
Options:
-c, --connections Connections to keep open
-d, --duration Duration of test
-t, --threads 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 跟服务器建立并保持的TCP连接数量
-d, --duration 压测时间
-t, --threads 使用多少个线程进行压测



-s, --script      <S>  指定Lua脚本路径       
-H, --header <H> 为每一个HTTP请求添加HTTP头
--latency 在压测结束后,打印延迟统计信息
--timeout <T> 超时时间
-v, --version 打印正在使用的wrk的详细版本信息


代表数字参数,支持国际单位 (1k, 1M, 1G)
代表时间参数,支持时间单位 (2s, 2m, 2h)
看下版本

wrk -v

输出:
wrk 4.0.2 [epoll] Copyright (C) 2012 Will Glozer


做一次简单压测,分析下结果

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


https://segmentfault.com/a/1190000014591330
https://github.com/wg/wrk

使用交互式命令
查看堆栈调用信息
go tool pprof http://localhost:6060/debug/pprof/heap
查看 30 秒内的 CPU 信息
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
查看 goroutine 阻塞
go tool pprof http://localhost:6060/debug/pprof/block
收集 5 秒内的执行路径
go tool pprof http://localhost:6060/debug/pprof/trace?seconds=5
争用互斥持有者的堆栈跟踪
go tool pprof http://localhost:6060/debug/pprof/mutex
UI web 界面
相比较于交互式命令行,这个UI分析工具就比较强大了,包括各种流程图式的分析,还有火焰图。但是会麻烦一点,首先我们得导出文件,下面例子是查看堆栈调用信息,其他相关信息需要调相关接口。

curl -sK -v http://localhost:6060/debug/pprof/heap > heap.out
然后用 go tool 工具 使用该导出文件起一个服务,会自动跳到 UI 界面。这个需要服务器安装 graphviz

go tool pprof -http=:8080 heap.out


Top:类似于 linux top 那种形式。从高到底排序
Graph:默认弹出来的就是该模式,也就是上一个图的那种带有调用关系的图。
Flame Graph:pprof 火焰图。
Peek:类似于 Top 也是从高到底的排序。
Source:和交互命令式的那种一样,带有源码标注。
Disassemble:显示所有的总量。

UI SAMPLE 为 VIEW 提供 4 种查询模式。

alloc_objects:已分配的对象总量(不管是否已释放)
alloc_space:已分配的内存总量(不管是否已释放)
inuse_objects: 已分配但尚未释放的对象数量
inuse_sapce:已分配但尚未释放的内存数量


1. 编写lua脚本,填写post的数据, 如  post.lua

wrk.method = "POST"

wrk.body  = '{"userId": "10001","coinType": "GT","type": "2","amount": "5.1"}'

wrk.headers["Content-Type"] = "application/json"

function request()

  return wrk.format('POST', nil, nil, body)

end

2. 执行wrk,开始压力测试:

wrk -t 16 -c 100 -d 30s --latency --timeout 5s -s post.lua http://localhost:8021/m/zh/order/new 


setup

线程出事后支持会调用一次。

init

每次请求发送之前被调用。可以接受 wrk 命令行的额外参数。

delay

这个函数返回一个数值,在这次请求执行完以后延迟多长时间执行下一个请求,可以对应 thinking time 的场景。

request

通过这个函数可以每次请求之前修改本次请求体和Header,我们可以在这里写一些要压力测试的逻辑。

response

每次请求返回以后被调用,可以根据响应内容做特殊处理,比如遇到特殊响应停止执行测试,或输出到控制台等等。



每个阶段做的是事如下:

setup : 线程出事后会调用一次,每个线程只调用一次
init : 每次请求发送之前被调用,可以接受wrk命令行的额外参数
delay : 这个函数返回一个数值,在这次请求执行完成后延迟多长时间可以进行下一个请求,对应thinking time场景
request : 通过这个函数可以每次请求之前修改本次请求体和Header, 这里是我们最常使用的地方,可以在这里写一些要压测的逻辑
response: 每次请求返回后可以针对响应内容做特殊处理,例如遇到特殊情况停止测试或输出到控制台上
done: 可以用于自定义结果报表,整个过程中只执行一次
2、wrk的全局属性

wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = ,
}
这些全局变量可以直接拿到lua脚本中使用 是一个table类型的wrk,为全局变量,修改这个table会影响所有的请求。

3、wrk的全局方法

-- 生成整个request的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)



1. 启动阶段:
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)
function delay()
function request()
function response(status, headers, body)
init(args):
由测试线程调用,只会在进入运行阶段时,调用一次。支持从启动 wrk 的命令中,获取命令行参数
delay():
每次发送请求之前调用,可以在这里定制延迟时间,通过返回值(单位毫秒)如:return 1000,即延迟一秒
request():
每次发送请求之前调用,可以对每一次的请求做一些自定义的操作,但是不要在该方法中做耗时的操作
response(status, headers, body):
在每次收到一个响应时被调用,为提升性能,如果没有定义该方法,为了提升效率,那么wrk不会解析 headers 和 body

结束阶段:
function done(summary, latency, requests)
done()
该方法和setup方法一样,只会被调用一次,整个测试完后执行,在定的参数中获取压测结果,生成定制化的测试报告

下面是官方对Lua API的说明


The public Lua API consists of a global table and a number of global functions:
wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = ,
}

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.

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.

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().

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)

The setup phase begins after the target IP address has been resolved and all
threads have been initialized but not yet started.

setup() is called once for each thread and receives a userdata object
representing the 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

Only boolean, nil, number, and string values or tables of the same may be
transfered via get()/set() and thread:stop() can only be called while the
thread is running.

Running

function init(args)
function delay()
function request()
function response(status, headers, body)

The running phase begins with a single call to init(), followed by
a call to request() and response() for each request cycle.

The init() function receives any extra command line arguments for the
script which must be separated from wrk arguments with "--".

delay() returns the number of milliseconds to delay sending the next
request.

request() returns a string containing the HTTP request. Building a new
request each time is expensive, when testing a high performance server
one solution is to pre-generate all requests in init() and do a quick
lookup in request().

response() is called with the HTTP response status, headers, and body.
Parsing the headers and body is expensive, so if the response global is
nil after the call to init() wrk will ignore the headers and body.

Done

function done(summary, latency, requests)

The done() function receives a table containing result data, and two
statistics objects representing the per-request latency and per-thread
request rate. Duration and latency are microsecond values and rate is
measured in requests per second.

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
}
}

Category golang