经过了两次更新,DCS_FunTester框架的基础功能已经接近尾声了,目前的状态基本能够使用,所以近期不会再进行功能更新了。
Part1Gradle多模块
由于之前一直写成了两个项目master
和slave
,考虑到这样使用多有不便,所以写到了一个Gradle
项目里面了。算是个小小地更新。也踩了踩Gradle
多模块项目的坑。
这里有几个坑,可以给大家分享一下:
1依赖另外模块
经过一顿乱操作,我找到了一种实现方式:
dependencies { implementation project(':slave')}
在网上搜了好几个教程都不管用,阴差阴错中我得到这个正确的解。而且在根目录下的build.gradle
文件中取消了设置项目子模块的设置,我也没懂到底Gradle
设置多模块的模板是什么样子的,算是积累成功经验吧。最近在使用Maven
作为构建工具开发新版的DCS_FunTester
感觉效果不错,感觉现在Maven
比两年前好用多了,特别是配合Intellij
使用的时候。
2子模块依赖
我搜到的资料将可以在父类模块的build.gradle
中配置子模块依赖,试过几次,其中都是使用以下方式:
subprojects{ dependencies{ ……万千依赖…… }}
但是始终无法成功,我猜想可能我在子模块中用到compile
或者说是依赖了本地的jar包,哪位大佬有知道的可以指点一二。
3setting.gradle
这个比较简单,大多数教程讲的都是对的。
rootProject.name = 'dcs_funtester'include 'slave'include 'master'
Part2结果收集
对于测试结果处理,我现在的思路就是汇总到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); } }
Part3任务分发
思路:当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 }
Part4探活接口
为了更好地管理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 } }
Part5优化注册机制
这个和上面探活有所关联,防止在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
。
道阻且艰,任重道远。