简单压测http-wrk

作者: 比轩 | 来源:发表于2019-11-03 19:15 被阅读0次

    关于压测

    常见的系统开发过程,压测总是被置于整个周期的末尾,比如项目基本功能开发完成或者临近上线时才开始准备压测。这个时候往往累积了大量的“小问题”,导致压测进行的比较缓慢,如果遇到前期“一压就崩”的状态则更让人奔溃。按照我的个人经验,压测之所以被经常性的忽略,不外乎压测脚本编写麻烦,场景梳理费时费力,而且特别占用开始时间等因素。其实如果不考虑复杂的业务场景,可以使用wrk/ad等简单http压测工具对刚完成开发的接口进行针对性压测,可以帮助后端开发人员更早的发现性能上的问题。

    wrk

    wrk 是一个简单小巧的 http 性能测试工具,只有一个命令行,就能做很多基本的 http 性能测试。

    wrk 本身是开源项目,代码在 github 上:https://github.com/wg/wrk

    安装

    wrk 具体的安装过程可以参考其 github上的wiki:https://github.com/wg/wrk/wiki

    本质上wrk只能运行在类Unix 的系统上,所以Win10其实要开启WSL(Windows SubLinux)才能正常安装使用。当然,官方wiki里都有提及,按照wiki中的提示操作即可。

    一键压测

    如果针对一个GET请求的Http接口,wrk基本上可以一键完成,比如:

    # 使用wrk创建12个线程
    # 维持 200 http并发连接
    # 对指定接口【GET www.baidu.com】进行持续30秒的压测
    wrk -t12 -c200 -d30s https://www.baidu.com
    
    压测baidu

    wrk命令的详细选项如下:

    • -c, --connections: http并发数(默认使用http1.1,会复用TCP链接)
    • -d, --duration: 持续压测时间, 比如: 2s, 2m, 2h
    • -t, --threads: 总线程数(建议为核心数的2倍即可)
      --s, --script: 指定执行Lua脚本(可以使用Lua脚本实现更高阶的功能)
    • -H, --header: 添加http header, 比如. -H 'Authorization: Bearer {token_value}' 来添加接口认证信息
    • --latency: 在控制台打印出延迟统计情况
    • --timeout: http超时时间

    用过lua脚本处理更复杂的情况

    用命令行其实已经可以覆盖很多简单的场景了。但是如果http接口稍微复杂些,就需要使用Lua脚本辅助。比如 接口为POST类型,body中有参数,响应需要写断言等等。

    比如下面这个简单的lua脚本,修改了全局对象wrk的三个属性,method,body,headers,最终所有发出的http请求都会被影响。

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

    Lua脚本执行的简单理解

    想要编写更加复杂的Lua脚本,需要了解wrk提供的几个hook函数。

    wrk提供的hook函数

    wrk 提供了几个 hook 函数,可以用 lua 来编写一些复杂场景下的测试:

    • setup

    这个函数在目标 IP 地址已经解析完,并且所有 thread 已经生成,但是还没有开始时被调用,每个线程执行一次这个函数。可以通过 thread:get(name), thread:set(name, value) 设置线程级别的变量。

    • init

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

    • delay

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

    • request

    通过这个函数可以每次请求之前修改本次请求的属性,返回一个字符串,这个函数要慎用, 会影响测试端性能。

    • response

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

    这里提供一个我自己使用的简单lua脚本

    -- 打印respose到控制台
    response = function(status, headers, body)
        -- 这里其实可以解析body,写断言,针对性打印比较好
        print("status:", status)
        print("body:", body)
    end
    
    -- 自定义分析压测结果
    done = function(summary, latency, requests)
    
        local durations=summary.duration / 1000000    -- 执行时间,单位是秒
        local errors=summary.errors.status            -- http status不是200,300开头的
        local requests=summary.requests               -- 总的请求数
        local valid=requests-errors                   -- 有效请求数=总请求数-error请求数
      
        io.write("Durations:       "..string.format("%.2f",durations).."s".."\n")
        io.write("Requests:        "..summary.requests.."\n")
        io.write("Avg RT:          "..string.format("%.2f",latency.mean / 1000).."ms".."\n")
        io.write("Max RT:          "..(latency.max / 1000).."ms".."\n")
        io.write("Min RT:          "..(latency.min / 1000).."ms".."\n")
        io.write("Error requests:  "..errors.."\n")
        io.write("Valid requests:  "..valid.."\n")
        io.write("QPS:             "..string.format("%.2f",valid / durations).."\n")
        io.write("--------------------------\n")
      
    end
    

    wrk源码中提供了一些常见的Lua脚本demo,可以参考:https://github.com/wg/wrk/tree/master/scripts

    建议

    其实这个建议就是官方的readme,简单翻一下:

    如果仅仅更改HTTP方法,修改路径,添加标头或正文的Lua脚本不会对压测的性能产生影响。但是针对每个请求的操作(特别是构建新的HTTP请求)以及使用 response()函数 必然会减少可以生成的负载量。

    A user script that only changes the HTTP method, path, adds headers or a body, will have no performance impact. Per-request actions, particularly building a new HTTP request, and use of response() will necessarily reduce the amount of load that can be generated.

    小技巧

    -H参数和curl-H参数含义一致,所以在实际使用中可以先使用curl确认编写的命令是否正确,或者也可以使用postman来确认,然后使用postman生成curl的请求命令即可。

    使用 postman 生成 curl 命令

    参考

    相关文章

      网友评论

        本文标题:简单压测http-wrk

        本文链接:https://www.haomeiwen.com/subject/wwllbctx.html