背景

  • 要用 wrk 进行压测
  • 看了下其他同事的压测,都用了 Lua 脚本来自定义一些东西
  • 所以这一篇主要讲 Lua 脚本

Lua 介绍

  • Lua 脚本是一种轻量小巧的脚本语言,用标准 c 语言编写,并以源代码形式开放
  • 其设计目的是为了嵌入应用程序中,从而为程序提供灵活的扩展和定制功能。
  • wrk 工具嵌入了 Lua 脚本语言
  • 因此,在自定义压测场景时,可在 wrk 目录下使用 Lua 定制压测场景

Lua 脚本的三个阶段

wrk 支持在三个不同的阶段执行 LuaJIT 脚本

  • setup:设置阶段
  • running:运行阶段
  • done:结束阶段

每个 wrk 线程都有一个独立的脚本环境,因为独有独立的 Lua 虚拟机

setup、done 阶段在一个单独的环境中执行,不参与 running 阶段

官方文档:https://github.com/wg/wrk/blob/master/SCRIPTING

POST 请求

前言

  • 之前说过,如果没有自定义的 Lua 脚本,wrk 默认发送的是 HTTP 1.1 GET 请求
  • 这里如果想发起 POST 请求的话,Lua 脚本要怎么写

官方脚本

-- POST 请求,演示如何添加
-- HTTP method, body, header wrk.method = "POST"
wrk.body = "foo=bar&baz=quux"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

wrk 变量

  • wrk 是一个内置的全局 table 类型变量,不需要定义可以直接使用
  • 修改 wrk 变量的值,会对所有请求都生效
wrk = {
scheme = "http",
host = "localhost",
port = nil,
method = "GET",
path = "/",
headers = {},
body = nil,
thread = <userdata>
}

wrk 内置函数

function wrk.format(method, path, headers, body)

  • 根据函数的参数和全局 wrk 变量,返回一个自定义的 http 请求字符串
  • 注意:函数的参数会覆盖 wrk 全局变量对应的参数值
  • 可以通过 format 可以构造出不同的 request

function wrk.lookup(host, service)

返回所有可用服务器的地址信息

function wrk.connect(addr)

  • 测试指定的服务器地址是否能正常连接
  • 如果地址可以连接到 wrk.connect,则返回true,否则返回false
  • 地址必须是从 wrk.lookup() 返回的地址

Lua 脚本三个阶段的内置函数

前言

上面也说到有三个阶段,setup、running、done 阶段,他们分别都有一些内置函数

setup 启动阶段

function setup(thread)

  • 每个线程初始化时执行一次,wrk 会在测试线程已经初始化但还没有启动的时候调用该方法
  • setup 方法会传入一个 thread 对象,可以修改或设置 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,终止线程
  • 只有布尔值、nil值、数字和字符串值或相同的 table 可以通过 get() / set() 进行操作
  • thread:stop() 只能在线程运行时被调用

running 运行阶段

function init(args)

  • 由线程调用,在线程开始启动时仅执行一次
  • args 是通过命令行传入的参数,通过 -- 指定

function delay()

  • 每次发送请求时,间隔时间(ms)
  • 每次发送请求前都会执行一次

function request()

  • 每次发送请求都会执行一次
  • 返回一个自定义的 HTTP 请求字符串

官方建议

  • 每次构建一个新的请求都很耗时耗资源
  • 当测试高性能服务器时,建议在 init() 中预生成所有请求,并在 request() 中进行快速查找

实际使用

  • 一般在这里会配合 wrk.format() 方法,动态创建请求
  • 这里不要执行耗时的代码,否则会影响测试结果准确性

function response(status, headers, body)

  • 每次请求得到响应时执行一次
  • 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
}
}

这个感觉不常用,用到再举栗子吧

具体的栗子

Lua 脚本

-- example script that demonstrates use of setup() to pass
-- data to and from the threads local counter = 1
local threads = {} function setup(thread)
-- 给每个线程设置一个 id 参数
thread:set("id", counter)
-- 将线程添加到 table 中
table.insert(threads, thread)
counter = counter + 1
end function init(args)
-- 初始化两个参数,每个线程都有独立的 requests、responses 参数
requests = 0
responses = 0 -- 打印线程被创建的消息,打印完后,线程正式启动运行
local msg = "thread %d created"
print(msg:format(id))
end function request()
-- 每发起一次请求 +1
requests = requests + 1
return wrk.request()
end function response(status, headers, body)
-- 每得到一次请求的响应 +1
responses = responses + 1
end function done(summary, latency, requests)
-- 循环线程 table
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

运行命令

wrk -d3s -c20 -t5 -s test.lua https://*****/get

运行结果

创建了 5 个线程, 以及每个线程发起的请求数和得到的响应数都有打印出来

工作上的模板栗子

Lua 脚本

为防止被盗,只放图片

官方脚本栗子

https://github.com/wg/wrk/tree/master/scripts

wrk(2)- Lua 脚本的使用的更多相关文章

  1. wrk中的lua脚本(转)

    转载地址:http://www.tuicool.com/articles/IFjIJjU wrk是一款现代化的http压测工具,提供lua脚本的功能可以满足每个请求或部分请求的差异化. wrk中执行h ...

  2. 在redis中使用lua脚本让你的灵活性提高5个逼格

    在redis的官网上洋洋洒洒的大概提供了200多个命令,貌似看起来很多,但是这些都是别人预先给你定义好的,但你却不能按照自己的意图进行定制, 所以是不是感觉自己还是有一种被束缚的感觉,有这个感觉就对了 ...

  3. 《转》Unity3D研究院编辑器之创建Lua脚本模板

    Unity里能创建 c#脚本模板,但是如果我想创建Lua脚本模板怎么办呢?拓展一下编辑器吧. 设置一下Lua脚本的模板地址 :  Assets/Editor/Lua/Template/lua.lua ...

  4. StackExchange.Redis加载Lua脚本进行模糊查询的批量删除和修改

    前言 使用StackExchange.Redis没有直接相关的方法进行模糊查询的批量删除和修改操作,虽然可以通过Scan相关的方法进行模糊查询,例如:HashScan("hashkey&qu ...

  5. 使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  6. redisTemplate的spring配置以及lua脚本驱动

    最近在使用spring-data-redis的redisTemplate,所以写篇使用记录吧. 1.不用多说,使用maven引入相关依赖,因为项目已经引入其他的 <dependency> ...

  7. redis原子性读写操作之LUA脚本和watch机制

    最近在开发电商平台的子系统--储值卡系统,系统核心业务涉及到金额消费以及库存控制,因此为了解决建立在内存上高并发情况下的事务控制,使用了spring封装的RedisTemplate执行lua脚本进行原 ...

  8. online_jf.lua --累计在线时间领取物品(积分)的lua脚本

    原作者: ayase 8-27修正 修复首次使用后的红字不需要额外进数据库导入计分表,这lua全自动生成 ----------------------------------------------- ...

  9. Redis执行Lua脚本的情况

    第一个测试: 往Redis里面存入1000个Hash,每个Hash里面有100个元素(Key 0-99,值是Key^2). PHP代码,执行33s左右 <?php $redis = new Re ...

随机推荐

  1. 编译Android 4.4源代码并烧录到Nexus4

    环境准备: 基本环境:ubuntu-12.04-desktop-64bit(裸机或者Windows下虚拟机安装均可,14.04也可以) 其他要求:空闲磁盘空间100G以上,代码部分接近10G,内存越大 ...

  2. ZOJ3261并查集逆向处理

    题意:       给你一些点,还有一些边,每个点上都有一个权值,然后有一些询问,分为两种, query a 询问与a直接或者间接想连的点中最大权值的是那个点,输出那个点,如果那个点的权值小于等于a的 ...

  3. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

  4. 【python】Leetcode每日一题-最长公共子序列

    [python]Leetcode每日一题-最长公共子序列 [题目描述] 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度.如果不存在 公共子序列 ,返回 0 . ...

  5. 【转】浅谈自动特征构造工具Featuretools

    转自https://www.cnblogs.com/dogecheng/p/12659605.html 简介 特征工程在机器学习中具有重要意义,但是通过手动创造特征是一个缓慢且艰巨的过程.Python ...

  6. .NET之API版本控制

    1. 优点 有助于保护原有系统,不受影响,并及时修改问题 可以实现用户的私人定制(比如是付费接口) 快速迭代 2. API版本控制 在URL中追加版本或者作为查询字符串参数 通过自动以标头和通过接受标 ...

  7. opencv——机器视觉检测和计数

    引言 在机器视觉中,有时需要对产品进行检测和计数.其难点无非是对于产品的图像分割. 由于之前网购的维生素片,有时候忘了今天有没有吃过,就想对瓶子里的药片计数...在学习opencv以后,希望实现对于维 ...

  8. MySQL角色(role)功能介绍

    前言: 上篇文章,我们介绍了 MySQL 权限管理相关知识.当数据库实例中存在大量的库或用户时,权限管理将会变得越来越繁琐,可能要频繁进行权限变更.MySQL 8.0 新增了 role 功能,使得权限 ...

  9. Codeforces Beta Round #107(Div2)

    B.Phone Numbers 思路:就是简单的结构体排序,只是这里有一个技巧,就是结构体存储的时候,直接存各种类型的电话的数量是多少就行,在读入电话的时候,既然号码是一定的,那么就直接按照格式%c读 ...

  10. 从系统的角度分析影响程序执行性能的因素——SA20225205 黄兴宇

    实验总结分析报告:从系统的角度分析影响程序执行性能的因素 1.请您根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的.自洽 ...