zoukankan      html  css  js  c++  java
  • wrk(2)- Lua 脚本的使用

    背景

    • 要用 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

  • 相关阅读:
    让原生select只读,即是有disabled的的感觉,但是却不实现disabled的功能
    log4j配置 简单jsp中调用查看报表配置 解析excel、txt为bean对象配置
    css背景渐变
    myeclipse始终build workspace
    spring实现重定向
    Mysql错误---
    POJ 1087 A Plug for UNIX 【最大流】
    POJ 3281 Dining 【最大流】【神建模】
    POJ 2135 Farm Tour 【模板】【最小费用最大流】
    LibreOJ 116 有源汇有上下界最大流 【模板】【上下界最大流】
  • 原文地址:https://www.cnblogs.com/poloyy/p/14872021.html
Copyright © 2011-2022 走看看