searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

性能测试工具之wrk

2023-07-31 05:07:59
25
0

简介

wrk 是一个类似 ab(apache bench)、jmeter 的 压力测试工具,底层基于 epoll 和 kqueue 实现,能充分利用 cpu 资源,降低测试工具本身性能开销对测试结果准确性的影响。支持使用 lua 脚本自定义测试逻辑,使用上非常简单,但功能足够强大。

用法

# GET 方法(默认),12 线程、400 连接、持续 30秒
$ wrk -t12 -c400 -d30s http://127.0.0.1:8080/test

说明

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)

Lua 脚本测试

# 指定脚本 myscript.lua
$ wrk -t12 -c400 -d30s -s myscript.lua http://127.0.0.1:8080/test

POST 请求

-- post.lua

-- example HTTP POST script which demonstrates setting the
-- HTTP method, body, and adding a header

wrk.method = "POST"
wrk.body   = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

API 说明

The public Lua API consists of a global table and a number of global functions.

全局变量

wrk 是一个内置的全局 table 类型变量,不需要定义可以直接使用,修改 wrk 变量的值,会对所有请求都生效。

wrk = {
  scheme  = "http",
  host    = "localhost",
  port    = nil,
  method  = "GET",
  path    = "/",
  headers = {},
  body    = nil,
  thread  = <userdata>
}

全局函数

wrk.format

生成请求 request

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.

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

生命周期回调函数

生命周期 3 个阶段:启动、运行、结束。

启动阶段

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)
function delay()
function request()
function response(status, headers, body)
结束阶段

done 返回结果时执行,整个测试过程只执行一次,可以生成自定义测试报告,如果没有特别需求,一般不重写这个方法。

function done(summary, latency, requests)
应用示例
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

测试示例

addr.lua

地址随机轮询

-- example script that demonstrates use of setup() to pass
-- a random server address to each thread

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
auth.lua

登录前置请求

-- example script that demonstrates response handling and
-- retrieving an authentication token to set on all future
-- requests

token = nil
path = "/authenticate"

request = function()
return wrk.format("GET", path)
end

response = function(status, headers, body)
if not token and status == 200 then
token = headers["X-Token"]
path = "/resource"
wrk.headers["X-Token"] = token
end
end
counter.lua

动态路径

-- example dynamic request script which demonstrates changing
-- the request path and a header for each request
-------------------------------------------------------------
-- NOTE: each wrk thread has an independent Lua scripting
-- context and thus there will be one counter per thread

counter = 0

request = function()
path = "/" .. counter
wrk.headers["X-Counter"] = counter
counter = counter + 1
return wrk.format(nil, path)
end
delay.lua

请求等待延迟

-- example script that demonstrates adding a random
-- 10-50ms delay before each request

function delay()
return math.random(10, 50)
end
pipeline.lua

流水线/串行请求

-- example script demonstrating HTTP pipelining

init = function(args)
local r = {}
r[1] = wrk.format(nil, "/?foo")
r[2] = wrk.format(nil, "/?bar")
r[3] = wrk.format(nil, "/?baz")

req = table.concat(r)
end

request = function()
return req
end
post.lua

POST 方法请求

-- example HTTP POST script which demonstrates setting the
-- HTTP method, body, and adding a header

wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
report.lua

打印测试报告

-- example reporting script which demonstrates a custom
-- done() function that prints latency percentiles as CSV

done = function(summary, latency, requests)
io.write("------------------------------\n")
for _, p in pairs({ 50, 90, 99, 99.999 }) do
n = latency:percentile(p)
io.write(string.format("%g%%,%d\n", p, n))
end
end
stop.lua

结束测试

-- example script that demonstrates use of thread:stop()

local counter = 1

function response()
if counter == 100 then
wrk.thread:stop()
end
counter = counter + 1
end

参考

0条评论
作者已关闭评论
萧****秀
5文章数
0粉丝数
萧****秀
5 文章 | 0 粉丝
萧****秀
5文章数
0粉丝数
萧****秀
5 文章 | 0 粉丝
原创

性能测试工具之wrk

2023-07-31 05:07:59
25
0

简介

wrk 是一个类似 ab(apache bench)、jmeter 的 压力测试工具,底层基于 epoll 和 kqueue 实现,能充分利用 cpu 资源,降低测试工具本身性能开销对测试结果准确性的影响。支持使用 lua 脚本自定义测试逻辑,使用上非常简单,但功能足够强大。

用法

# GET 方法(默认),12 线程、400 连接、持续 30秒
$ wrk -t12 -c400 -d30s http://127.0.0.1:8080/test

说明

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)

Lua 脚本测试

# 指定脚本 myscript.lua
$ wrk -t12 -c400 -d30s -s myscript.lua http://127.0.0.1:8080/test

POST 请求

-- post.lua

-- example HTTP POST script which demonstrates setting the
-- HTTP method, body, and adding a header

wrk.method = "POST"
wrk.body   = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

API 说明

The public Lua API consists of a global table and a number of global functions.

全局变量

wrk 是一个内置的全局 table 类型变量,不需要定义可以直接使用,修改 wrk 变量的值,会对所有请求都生效。

wrk = {
  scheme  = "http",
  host    = "localhost",
  port    = nil,
  method  = "GET",
  path    = "/",
  headers = {},
  body    = nil,
  thread  = <userdata>
}

全局函数

wrk.format

生成请求 request

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.

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

生命周期回调函数

生命周期 3 个阶段:启动、运行、结束。

启动阶段

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)
function delay()
function request()
function response(status, headers, body)
结束阶段

done 返回结果时执行,整个测试过程只执行一次,可以生成自定义测试报告,如果没有特别需求,一般不重写这个方法。

function done(summary, latency, requests)
应用示例
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

测试示例

addr.lua

地址随机轮询

-- example script that demonstrates use of setup() to pass
-- a random server address to each thread

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
auth.lua

登录前置请求

-- example script that demonstrates response handling and
-- retrieving an authentication token to set on all future
-- requests

token = nil
path = "/authenticate"

request = function()
return wrk.format("GET", path)
end

response = function(status, headers, body)
if not token and status == 200 then
token = headers["X-Token"]
path = "/resource"
wrk.headers["X-Token"] = token
end
end
counter.lua

动态路径

-- example dynamic request script which demonstrates changing
-- the request path and a header for each request
-------------------------------------------------------------
-- NOTE: each wrk thread has an independent Lua scripting
-- context and thus there will be one counter per thread

counter = 0

request = function()
path = "/" .. counter
wrk.headers["X-Counter"] = counter
counter = counter + 1
return wrk.format(nil, path)
end
delay.lua

请求等待延迟

-- example script that demonstrates adding a random
-- 10-50ms delay before each request

function delay()
return math.random(10, 50)
end
pipeline.lua

流水线/串行请求

-- example script demonstrating HTTP pipelining

init = function(args)
local r = {}
r[1] = wrk.format(nil, "/?foo")
r[2] = wrk.format(nil, "/?bar")
r[3] = wrk.format(nil, "/?baz")

req = table.concat(r)
end

request = function()
return req
end
post.lua

POST 方法请求

-- example HTTP POST script which demonstrates setting the
-- HTTP method, body, and adding a header

wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"
report.lua

打印测试报告

-- example reporting script which demonstrates a custom
-- done() function that prints latency percentiles as CSV

done = function(summary, latency, requests)
io.write("------------------------------\n")
for _, p in pairs({ 50, 90, 99, 99.999 }) do
n = latency:percentile(p)
io.write(string.format("%g%%,%d\n", p, n))
end
end
stop.lua

结束测试

-- example script that demonstrates use of thread:stop()

local counter = 1

function response()
if counter == 100 then
wrk.thread:stop()
end
counter = counter + 1
end

参考

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0