zoukankan      html  css  js  c++  java
  • DCS_FunTester分布式压测框架更新(三)

    经过了两次更新,DCS_FunTester框架的基础功能已经接近尾声了,目前的状态基本能够使用,所以近期不会再进行功能更新了。

    Gradle多模块

    由于之前一直写成了两个项目masterslave,考虑到这样使用多有不便,所以写到了一个Gradle项目里面了。算是个小小地更新。也踩了踩Gradle多模块项目的坑。

    这里有几个坑,可以给大家分享一下:

    依赖另外模块

    经过一顿乱操作,我找到了一种实现方式:

    dependencies {
        implementation project(':slave')
    }
    

    在网上搜了好几个教程都不管用,阴差阴错中我得到这个正确的解。而且在根目录下的build.gradle文件中取消了设置项目子模块的设置,我也没懂到底Gradle设置多模块的模板是什么样子的,算是积累成功经验吧。

    最近在使用Maven作为构建工具开发新版的DCS_FunTester感觉效果不错,感觉现在Maven比两年前好用多了,特别是配合Intellij使用的时候。

    子模块依赖

    我搜到的资料将可以在父类模块的build.gradle中配置子模块依赖,试过几次,其中都是使用以下方式:

    subprojects{
     dependencies{
        ……万千依赖……
     }
    }
    

    但是始终无法成功,我猜想可能我在子模块中用到compile或者说是依赖了本地的jar包,哪位大佬有知道的可以指点一二。

    setting.gradle

    这个比较简单,大多数教程讲的都是对的。

    rootProject.name = 'dcs_funtester'
    include 'slave'
    include 'master'
    

    结果收集

    对于测试结果处理,我现在的思路就是汇总到master节点,然后统一由master节点管理,无论是入库也好、合并计算也好。

    这里在slave节点执行用例的结束的时候,会把结果同步到master节点。

    下面执行单个请求时候的Demo:

        @Async
        @Override
        public void runRequest(HttpRequest request) {
            BaseRequest r = request.getRequest();
            HttpRequestBase re = FunRequest.initFromJson(r.toJson()).getRequest();
            Integer times = request.getTimes();
            String mode = request.getMode();
            Integer thread = request.getThread();
            Integer runup = request.getRunup();
            String desc = request.getDesc();
            if (mode.equalsIgnoreCase("ftt")) {
                Constant.RUNUP_TIME = runup;
                RequestThreadTimes task = new RequestThreadTimes(re, times);
                Concurrent concurrent = new Concurrent(task, thread, desc);
                PerformanceResultBean resultBean = concurrent.start();
                SlaveManager.updateResult(resultBean, request.getMark());
            }
        }
    

    对应master节点的接口controller代码如下:

        @ApiOperation(value = "更新测试结果")
        @ApiImplicitParam(name = "bean", value = "测试结果对象", dataTypeClass = PerformanceResultBean.class)
        @PostMapping(value = "/upresult/{mark}")
        public Result updateResult(@PathVariable(value = "mark") int mark, @RequestBody PerformanceResultBean bean) {
            NodeData.addResult(mark, bean)
            Result.success()
        }
    

    service伪代码,这里我直接放在了JVM里面,没有持久化入库,因为这个功能可能在未来会被抛弃,使用服务端统计来代替压力机统计结果。

        /**
         * 添加运行信息
         *
         * @param bean
         */
        public static void addResult(int mark, PerformanceResultBean bean) {
            synchronized (results) {
                results.computeIfAbsent(mark, f -> new ArrayList<PerformanceResultBean>());
                results.get(mark).add(bean);
            }
        }
    

    任务分发

    思路:当master节点收到任务之后,首先对比任务信息中对节点的需求和当前可使用节点数量。如果足够,获取相应节点,向节点发送执行任务,当所有节点都接受成功之后,返回成功。如果其中失败的,那么回滚已经开始执行的节点,返回失败。

    这里分享一个执行单接口请求的Demo:

        @Override
        int runRequest(HttpRequest request) {
            def num = request.getMark()
            def hosts = NodeData.getRunHost(num)
            def mark = SourceCode.getMark()
            request.setMark(mark)
            try {
                hosts.each {
                    def re = MasterManager.runRequest(it, request)
                    if (!re) FailException.fail()
                    NodeData.addTask(it, mark)
                }
            } catch (FailException e) {
                hosts.each {f -> MasterManager.stop(f)}
                FailException.fail("多节点执行失败!")
            }
            mark
        }
    

    探活接口

    为了更好地管理slave节点的状态,本次更新增加了slave节点的探活接口。由master节点定时去探活,而不仅仅依靠slave节点上报,这个接口作为临时接口,保障了在slave节点频繁上下线导致master节点出现故障。

    后期这个功能也会下线,因为我计划使用nacos对用例状态进行维护,这个也是听从大佬的建议,使用优秀的管理组件,能够节省大量时间和提升可靠性。

    slave节点探活接口:

        @ApiOperation(value = "节点状态,是否存活")
        @GetMapping(value = "/alive")
        public Result alive() {
            return Result.success();
        }
    
    

    master节点实现方式:

        /**
         * 节点是否存活
         * @param host
         * @return
         */
        static boolean alive(String host) {
            try {
                String url = SlaveApi.ALIVE;
                return isRight(getGetResponse(host, url, null))
            } catch (Exception e) {
                logger.warn("节点: {}探活失败!", host)
                return false
            }
        }
    
    

    优化注册机制

    这个和上面探活有所关联,防止在slave节点可以访问master节点,但是反过来无法访问的情况下,master节点出现无效的slave节点情况,这里在slave节点注册时候,增加了探活步骤。

    controller代码如下:

        @ApiOperation(value = "注册接口")
        @PostMapping(value = "/register")
        public Result register(@Valid @RequestBody RegisterBean bean) {
            def url = bean.getUrl()
            def stop = MasterManager.alive(url)
            if (!stop) FailException.fail("注册失败!")
            NodeData.register(url, false)
            Result.success()
        }
    
    
    • DCS_FunTester开发告一段落,基本的功能都已具备,下一步是结合管理组件,实现更好的管理。还有就是结合业务开发响应的功能。最近也在学习nacos

    道阻且艰,任重道远。

    Have Fun ~ Tester !

  • 相关阅读:
    找零问题-完全背包
    可同时在nodejs和浏览器端使用的websocket
    C++ vector 比较大小
    npm ERR! Unexpected token in JSON at position 0 while parsing near '<HTML> 解决办法
    C/C++宏定义中#与##区别
    解析日志工具。
    3
    2
    dssfsfsfs
    android获取USB设备的名称
  • 原文地址:https://www.cnblogs.com/FunTester/p/15165049.html
Copyright © 2011-2022 走看看