zoukankan      html  css  js  c++  java
  • 使用 WRK 压力测试工具对 ASP.NET Core 的接口进行压力测试

    0. 简要介绍

    WRK 是一款轻量且易用的 HTTP 压力测试工具,通过该工具我们可以方便地对我们所开发的 WebAPI 项目进行压力测试,并且针对测试的情况返回结果。

    PS:Wrk 并不能针对测试的结果生成动态的图表,如果有这种需要,可以尝试使用另一款工具 Vegeta。该项目使用的 Golang 进行编写,其 GitHub 地址为:https://github.com/tsenart/vegeta

    下面的内容就是一个标准的测试结果信息:

    # 针对 127.0.0.1:8080 进行压力测试
    wrk -t12 -c400 -d30s http://127.0.0.1:8080/index.html
    
    # 这里是测试结果
    Running 30s test @ http://127.0.0.1:8080/index.html
      12 threads and 400 connections
      Thread Stats   Avg      Stdev     Max   +/- Stdev
        Latency   635.91us    0.89ms  12.92ms   93.69%
        Req/Sec    56.20k     8.07k   62.00k    86.54%
      22464657 requests in 30.00s, 17.76GB read
    Requests/sec: 748868.53
    Transfer/sec:    606.33MB
    

    1. 安装

    关于 OS X 与 Windows 的安装可以参考 Wrk 官方 WIKI 进行操作,本文主要讲解一下 CentOS 7.x 下如果进行编译。

    sudo yum groupinstall 'Development Tools'
    sudo yum install -y openssl-devel git 
    git clone https://github.com/wg/wrk.git wrk
    cd wrk
    make
    

    编译之后,你会得到如下结果:

    可以看到生成了一个 wrk 的可执行文件,你可以将其添加到环境变量的 PATH 当中,这里就不再赘述,我们等会儿使用的时候直接 ./wrk 使用。

    2. 命令说明

    ./wrk -H "Authorization: Bearer TokenValue" -t 2 -c 50 -d 10s --latency --timeout 1s "http://"
    

    上面的命令就是一个典型的压力测试命令,关于参数的含义请看下表。

    执行命令时的参数 含义 示例
    -c 与 HTTP 保持连接的连接数,最终每个线程能够处理的为 连接数/线程数。 -c 50
    -d 指定压力测试的时间有多长。 -d 10s,其他单位有 2s,2m,2h
    如果不带单位的话,默认为秒。
    -t 压力测试时所使用的线程数目,最好为你 CPU 核心的数量。 -t 4
    -s 指定要执行的 Lua 脚本 -s ./post.lua
    -H 执行请求的时候所附带的 Header 组。 -H "User-Agent: wrk"
    --latency 打印详细的统计信息。 --latency
    --timeout 每次请求所返回响应体的时间,如果超过了配置的时间,则视为请求超时。 --timeout 1s

    3. 开始压力测试

    执行了上述代码之后我们可以看到很直观的信息,第一个就是 20s 的时间内完成了 2887 次请求,一共接受到了 2.46MB 的数据。在 Socket errors 里面我们可以看到有 35 个请求产生了超时的情况,每秒执行的请求大概为 144.20 个,每秒的数据传输大概为 125.75 KB。

    除此之外,还说明了平均每次请求所消耗的时间为 338.44 ms,最极端的情况为 994.27ms。

    4. LUA 脚本

    在第三节我们可以看到一些标准的 GET 请求我们可以直接通过指定命令来进行测试,即便该接口有授权验证,我们可以通过 -H 参数来指定 Authorization 头来实现权限验证。
    但是针对一些复杂的情况,我们就需要编写 LUA 脚本来实现压力测试了。

    官方编写了很多的 LUA 脚本 DEMO ,存放在 GitHub 上面,其地址为:https://github.com/wg/wrk/tree/master/scripts

    这里我们以实现 POST 请求为例:

    wrk.method = "POST"
    wrk.body   = '{"username":"admin","password":"123qwe","rememberClient":true}'
    wrk.headers["Content-Type"] = "application/json"
    

    这里我们的接口地址更改了一下,改变成了 Login 接口,该接口需要传入用户名与密码,并且其 Method 为 POST。

    将上述 LUA 脚本保存为 post.lua 文件,然后通过 -s 参数指定 LUA 脚本的路径并执行。

    5. LUA 脚本相关详解

    WRK 中执行 HTTP 请求的时候,调用 Lua 分为 3 个阶段,setuprunningdone,每个 WRK 线程中都有独立的脚本环境。

    5.1 WRK 的全局属性

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

    5.2 WRK 的全局方法

    -- 生成整个request的string,例如:返回
    -- GET / HTTP/1.1
    -- Host: tool.lu
    function wrk.format(method, path, headers, body)
    
    -- 获取域名的IP和端口,返回table,例如:返回 `{127.0.0.1:80}`
    function wrk.lookup(host, service)
    
    -- 判断addr是否能连接,例如:`127.0.0.1:80`,返回 true 或 false
    function wrk.connect(addr)
    

    5.3 Setup 阶段

    setup() 方法是在线程创建之后,启动之前。

    function setup(thread)
    
    -- thread提供了1个属性,3个方法
    -- thread.addr 设置请求需要打到的ip
    -- thread:get(name) 获取线程全局变量
    -- thread:set(name, value) 设置线程全局变量
    -- thread:stop() 终止线程
    

    5.4 Running 阶段

    function init(args)
    -- 每个线程仅调用1次,args 用于获取命令行中传入的参数, 例如 --env=pre
    
    function delay()
    -- 每个线程调用多次,发送下一个请求之前的延迟, 单位为ms
    
    function request()
    -- 每个线程调用多次,返回http请求
    
    function response(status, headers, body)
    -- 每个线程调用多次,返回http响应
    

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

    而官方的 setup.lua 脚本则是重载这些方法并使用的一个 DEMO:

    -- example script that demonstrates use of setup() to pass
    -- data to and from the threads
    
    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
    

    6. 参考资料

    wrk中的lua脚本:https://type.so/linux/lua-script-in-wrk.html

    http 性能测试 wrk使用教程:https://juejin.im/post/5a59e74f5188257353008fea

  • 相关阅读:
    未将对象引用设置到对象的实例--可能出现的问题总结
    Unity3d物体模型(实现旋转缩放平移自动旋转)
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java实现斐波那契数列的多种方法
    Java中环境变量PATH与CLASSPATH的区别
    Java中环境变量PATH与CLASSPATH的区别
    Java中环境变量PATH与CLASSPATH的区别
  • 原文地址:https://www.cnblogs.com/myzony/p/9798116.html
Copyright © 2011-2022 走看看