前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于docker的分布式性能测试框架功能验证(一)

基于docker的分布式性能测试框架功能验证(一)

作者头像
FunTester
发布2021-06-23 10:39:54
3920
发布2021-06-23 10:39:54
举报
文章被收录于专栏:FunTesterFunTester

本文是「FunTester」测试框架分布式性能测试功能拓展实践,是一种比较粗略的技术验证实践,技术方案采用分布式性能测试框架用例方案设想(一)中所设想场景。

粗实现方案分成三块:「master调度机」「slave测试机」「server被测服务」

  • master调度机:处理用例、分配任务
  • slave测试机:接受任务、执行用例
  • server被测服务:提供测试接口

docker镜像

刚开始学,学了点皮毛,这里只分享几个简单步骤,各位要是有兴趣的话,还是需要一个完成的docker教程的。

基础镜像

这里我选择了Groovy:latest版本作为基础镜像,里面是Groovy 3.0.8,各位使用的使用请注意这个版本需要跟自己项目依赖的Groovy版本一致,不然会报错:

代码语言:javascript
复制
Caused by: groovy.lang.GroovyRuntimeException: Conflicting module versions. Module [groovy-xml is loaded in version 3.0.8 and you are trying to load version 2.5.7

启动容器

使用命令docker run -it -u 0 --name funtester aed55a7f14d3 /bin/bash启动容器,这里参数-u 0使用root身份登录,不然会使用groovy账户登录,导致权限不足的报错。

设置网络

因为我的「master调度机」放在本机了,所以多了一个设置容器访问本地主机端口的步骤。

请参考官网文档:

❝主机的IP地址正在更改(如果没有网络访问权限,则没有IP地址)。我们建议您连接到特殊的DNS名称host.docker.internal,该名称 解析为主机使用的内部IP地址。这是出于开发目的,不适用于Docker Desktop for Windows以外的生产环境。 ❞

这个功能在安装docker desktop的时候已经默认打开了,所以直接用域名host.docker.internal替换localhost即可访问「master调度机」服务接口。

安装vim

安装vimapt-get update && apt-get install apt-file -y && apt-file update && apt-get install vim

更新依赖

这里需要使用docker cp命令将本机打包好的jar包,推送到容器中的Groovy lib目录中。

更新镜像

使用命令:docker commit -a "funtester" -m "update groovy" c9596359c1d1 funtester/groovy:v1

更新脚本

将写好的脚本推送到容器中,然后启动对应的脚本(下面会分享),就可以执行验证工作了。这里应当使用dockerfile,原谅我才看了两天,dockerfile还不是很熟练,我打算放在Springboot项目中编写dockerfile文件。

master调度机

这里我只实现了一种调度功能:就是提供一个接口,该接口返回一个测试用例(尚未封装对象)。提供给「slave测试机」请求,返回给测试机测试任务(测试用例)。

听起来这是一个服务了,但是我现在还没开始写Springboot项目,只能用funtester moco server代替了这个功能。对于用例管理等其他功能还没有实现。

master脚本

代码语言:javascript
复制
import com.alibaba.fastjson.JSONObject
import com.funtester.base.bean.Result
import com.funtester.httpclient.FunLibrary
import com.funtester.httpclient.FunRequest
import com.mocofun.moco.MocoServer
import com.sun.deploy.ui.FancyButton
import org.apache.http.client.methods.HttpGet

class DcsServer extends MocoServer {

    public static void main(String[] args) {
        def server = getServer(12345)
        def res = new JSONObject()
        res.times = 1000
        res.thread = 20
        res.mode = "ftt"
        res.desc = "FunTester分布式测试Demo"
        res.runup = 10
        String url = "http://192.168.80.169:12345/m"
        def get = FunLibrary.getHttpGet(url)
        def request = FunRequest.initFromRequest(get)
        res.request = request
        output(res)
        server.get(urlStartsWith("/m")).response(obRes(Result.success(res)))

        def run = run(server)

        waitForKey("fun")

        run.stop()

    }
}

其中http://192.168.80.169:12345/m是被测服务暴露的测试接口,也是用funtester moco server做的,后面也会分享脚本内容。

这里我根据测试机中方法com.funtester.httpclient.FunRequest#initFromString和一些必要的参数创建了一个JSON格式的接口返回。其中在request赋值的时候,我采用的方式是:

代码语言:javascript
复制
        def request = FunRequest.initFromRequest(get)
        res.request = request

能省去不少麻烦,直接把request对象放到响应结果中。

下面是具体的响应结果:

代码语言:javascript
复制
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
>  {
>  ① . "code":0,
>  ① . "data":{
>  ② . . . "mode":"ftt",
>  ② . . . "request":{
>  ③ . . . . . "args":{
>  ④ . . . . . . . 
>  ③ . . . . . },
>  ③ . . . . . "headers":[
>  ④ . . . . . . . 
>  ③ . . . . . ],
>  ③ . . . . . "path":"",
>  ③ . . . . . "request":{
>  ④ . . . . . . . "allHeaders":[
>  ⑤ . . . . . . . . . 
>  ④ . . . . . . . ],
>  ④ . . . . . . . "method":"GET",
>  ④ . . . . . . . "aborted":false,
>  ④ . . . . . . . "protocolVersion":{
>  ⑤ . . . . . . . . . "protocol":"HTTP",
>  ⑤ . . . . . . . . . "major":1,
>  ⑤ . . . . . . . . . "minor":1
>  ④ . . . . . . . },
>  ④ . . . . . . . "requestLine":{
>  ⑤ . . . . . . . . . "method":"GET",
>  ⑤ . . . . . . . . . "protocolVersion":{
>  ⑥ . . . . . . . . . . . "$ref":"$.data.request.request.protocolVersion"
>  ⑤ . . . . . . . . . },
>  ⑤ . . . . . . . . . "uri":"http://192.168.80.169:12345/m"
>  ④ . . . . . . . },
>  ④ . . . . . . . "params":{
>  ⑤ . . . . . . . . . "names":[
>  ⑥ . . . . . . . . . . . 
>  ⑤ . . . . . . . . . ]
>  ④ . . . . . . . },
>  ④ . . . . . . . "uRI":"http://192.168.80.169:12345/m"
>  ③ . . . . . },
>  ③ . . . . . "requestType":"GET",
>  ③ . . . . . "response":{
>  ④ . . . . . . . "code":-2,
>  ④ . . . . . . . "FunTester":200,
>  ④ . . . . . . . "content":"hello funtester!!!"
>  ③ . . . . . },
>  ③ . . . . . "host":"",
>  ③ . . . . . "json":{
>  ④ . . . . . . . 
>  ③ . . . . . },
>  ③ . . . . . "params":{
>  ④ . . . . . . . 
>  ③ . . . . . },
>  ③ . . . . . "uri":"http://192.168.80.169:12345/m"
>  ② . . . },
>  ② . . . "times":1000,
>  ② . . . "thread":20,
>  ② . . . "runup":10,
>  ② . . . "desc":"FunTester分布式测试Demo"
>  ① . },
>  ① . "success":true
>  }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~

可以看到在data.request节点中,很多信息都是重复的,这并不影响,因为data.request节点下的key我只会取有用的,这个在设计方案时已经说明了,request信息除了com.funtester.httpclient.FunRequest对象属性外,都是从使用fastjson提供的工具类对org.apache.http.client.methods.HttpRequestBase进行序列化得到的。

slave测试机

这个逻辑通过简单的轮询去master调度机提供的接口获取测试任务或者测试用例。然后解析,执行测试用例。

脚本如下:

代码语言:javascript
复制

import com.funtester.config.Constant
import com.funtester.frame.execute.Concurrent
import com.funtester.frame.thread.RequestThreadTimes
import com.funtester.httpclient.FunLibrary
import com.funtester.httpclient.FunRequest

class Dcs extends FunLibrary {

    public static void main(String[] args) {
        while (true) {
            String url = "http://host.docker.internal:12345/m"
            //请求此接口会返回一个用例,目前没有用对象封装
            //            String url = "http://localhost:12345/m"//本机调试用的
            def get = getHttpGet(url)
            def response = getHttpResponse(get)
            if (response.getInteger("code") == 0) {
                def data = response.getJSONObject("data")
                def r = data.getString("request")
                /*此处以后会简化成一个对象*/
                def request = FunRequest.initFromString(r).getRequest()
                //压测模式
                def times = data.getIntValue("times")
                //测试终止条件
                def mode = data.getString("mode")
                //线程数,这里默认固定线程模式
                def thread = data.getIntValue("thread")
                //软启动时间
                def runup = data.getIntValue("runup")
                //用例描述
                def desc = data.getString("desc")
                if (mode == "ftt") {
                    Constant.RUNUP_TIME = runup
                    def task = new RequestThreadTimes(request, times)
                    def performanceResultBean = new Concurrent(task, thread, desc).start()
                }
            }
            sleep(5.0)
        }
    }
}

后期应该会把每个不同的响应体中data封装成不同的对象,这样处理数据会比较简单。

关于测试mode,目前支持了四种(固定线程|固定QPS * 限制请求次数|限制请求时间),之前都分享过了,这里就不多说。

server被测服务

同样采用了funtester moco serverr编写,脚本如下:

代码语言:javascript
复制
import com.mocofun.moco.MocoServer

class TestDemo extends MocoServer{

    static void main(String[] args) {
        def log = getServer(12345)
        log.response("hello funtester!!!")


        def run = run(log)
        waitForKey("fan")
        run.stop()


    }
}

这次我没有屏蔽日志,这样比较方便观察「slave测试机」是请求是否正确,单词请求的日志内容如下:

代码语言:javascript
复制

Request received:

GET /m HTTP/1.1
Host: 192.168.80.169:12345
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.6 (Java/1.8.0_282)
Accept-Encoding: gzip,deflate
content-length: 0

Response return:

HTTP/1.1 200
Content-Length: 18
Content-Type: text/plain; charset=utf-8

hello funtester!!!

「FunTester」,腾讯云年度作者Boss直聘签约作者GDevOps官方合作媒体,非著名测试开发。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • docker镜像
    • 基础镜像
      • 启动容器
        • 设置网络
          • 安装vim
            • 更新依赖
              • 更新镜像
                • 更新脚本
                • master调度机
                  • master脚本
                    • slave测试机
                      • server被测服务
                      相关产品与服务
                      容器服务
                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档