写点什么

性能测试中集合点和多阶段问题初探

用户头像
FunTester
关注
发布于: 10 小时前

在性能测试过程中,场景会遇到一些场景,需要在各种准备条件满足的情况下才能开始进行性能测试。例如:我需要 200 个学生进行一个单接口的压测,首先我得让这 200 个学生都登录,然后才能用 200 个User对象发起接口请求。


在以往的经历中,我更偏向于串行的方式去登录 200 个学生,然后再创建压测ThreadBase对象进行性能测试,由于前期消耗时间比较短,也就一直没有进行优化。在学习了CyclicBarrier类在性能测试中应用之后,一直有个想法就是将这段准备时间压缩,多线程去执行,然后在某一个时刻再开始压测任务的执行。基本思路就是使用Java多线程编程类CyclicBarrier解决性能测试中多线程的集合点设置和多阶段性能测试问题。


这里我用了一个链路压测的脚本进行改造,原版的脚本大家可以参考:链路压测中如何记录每一个耗时的请求,如果对链路压测感兴趣的还可以参考以前的文章:


思路

在创建ThreadBase对象的时候,引入一个线程安全类AtomicInteger来标记每一个线程使用的用户账号和密码,区分不同线程使用不同的用户。


集合点的设置,我设置了两处:一是执行before(),用于等待所有线程的用户基类OkayBase和用户业务模块类OKclass对象初始化。二是在执行after()方法中,用于标记一下所有线程执行完毕,这里有些多余,因为在ThreadBase中,我设置了一个CountDownLatch对象的属性,用于等待所有线程任务执行完毕。这里只是为了演示一下CyclicBarrier多阶段同步的使用。


ThreadBase类的after()方法内容如下:


    /**     * 运行待测方法后的处理     */    protected void after() {        if (countDownLatch != null)            countDownLatch.countDown();    }
复制代码

Demo 实践

代码中我注释掉了实际的业务请求,只写了两个sleep()方法和一个日志输出。


package com.okayqa.composer.performance.master1_0
import com.fun.base.constaint.ThreadLimitTimesCountimport com.fun.frame.execute.Concurrentimport com.fun.frame.httpclient.ClientManageimport com.fun.utils.ArgsUtilimport com.okayqa.composer.base.OkayBaseimport com.okayqa.composer.function.OKClassimport org.slf4j.Loggerimport org.slf4j.LoggerFactory
import java.util.concurrent.CyclicBarrierimport java.util.concurrent.TimeUnitimport java.util.concurrent.atomic.AtomicInteger
class BothCollectCopy extends OkayBase {
private static Logger logger = LoggerFactory.getLogger(BothCollectCopy.class)
static AtomicInteger u = new AtomicInteger(0)
static int times = 0
static int thread
static CyclicBarrier cyclicBarrier
public static void main(String[] args) { ClientManage.init(5, 1, 0, "", 0) def util = new ArgsUtil(args) thread = util.getIntOrdefault(0, 5) times = util.getIntOrdefault(1, 2)
cyclicBarrier = new CyclicBarrier(thread, new Runnable() {
@Override void run() { logger.info("到达人数 {} ", cyclicBarrier.getParties())
} })
def funs = [] thread.times { funs << new Fun() } new Concurrent(funs, "收藏和取消收藏").start() allOver() }
static int getTimes() { return times }
static class Fun extends ThreadLimitTimesCount {
OkayBase okayBase
OKClass driver
public Fun() { super(null, getTimes(), null) }
@Override void before() { super.before() okayBase = getBase(u.getAndIncrement()) driver = new OKClass(okayBase) cyclicBarrier.await(10, TimeUnit.SECONDS) }
@Override protected void after() { super.after() cyclicBarrier.await(100,TimeUnit.SECONDS) }
@Override protected void doing() throws Exception {// def collect = driver.collect()// def value = okayBase.getLastRequestId() + CONNECTOR// this.threadmark += value// if (collect.getJSONObject("meta").getIntValue("ecode") != 0) fail(value + "请求出错!")// def collect1 = driver.unCollect()// def value1 = okayBase.getLastRequestId()// this.threadmark += value1// if (collect1.getJSONObject("meta").getIntValue("ecode") != 0) fail(value1 + "请求出错!") sleep(1.0) logger.info(this.threadName) sleep(1.0) } }
}
复制代码

控制台输出

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/okay_test/,系统编码格式:UTF-8,系统Mac OS X版本:10.16INFO-> requestid: Fdev16093173246753INFO-> requestid: Fdev16093173245764INFO-> requestid: Fdev16093173244862INFO-> requestid: Fdev16093173243871INFO-> requestid: Fdev16093173248887INFO-> 请求uri:https://teacherpad-d***/api/t_pad/user/login,耗时:453 msINFO-> 请求uri:https://teacherpad***.cn/api/t_pad/user/login,耗时:433 msINFO-> 教师:61951375269,学科:null,名称:61951375269,登录成功!INFO-> 教师:61951377260,学科:null,名称:61951377260,登录成功!INFO-> 请求uri:https://teacherpad***n/api/t_pad/user/login,耗时:459 msINFO-> 教师:61951377259,学科:null,名称:61951377259,登录成功!INFO-> 请求uri:https://teacherpad**cn/api/t_pad/user/login,耗时:488 msINFO-> 教师:61951375951,学科:null,名称:61951375951,登录成功!INFO-> 请求uri:https://teacherpad-**cn/api/t_pad/user/login,耗时:690 msINFO-> 教师:61951377261,学科:null,名称:61951377261,登录成功!INFO-> 到达人数 5 INFO-> 收藏和取消收藏0INFO-> 收藏和取消收藏2INFO-> 收藏和取消收藏3INFO-> 收藏和取消收藏1INFO-> 收藏和取消收藏4INFO-> 收藏和取消收藏4INFO-> 收藏和取消收藏0INFO-> 收藏和取消收藏2INFO-> 收藏和取消收藏1INFO-> 收藏和取消收藏3INFO-> 线程:收藏和取消收藏1,执行次数:2,错误次数: 0,总耗时:5 sINFO-> 线程:收藏和取消收藏0,执行次数:2,错误次数: 0,总耗时:5 sINFO-> 线程:收藏和取消收藏4,执行次数:2,错误次数: 0,总耗时:5 sINFO-> 线程:收藏和取消收藏3,执行次数:2,错误次数: 0,总耗时:5 sINFO-> 线程:收藏和取消收藏2,执行次数:2,错误次数: 0,总耗时:5 sINFO-> 到达人数 5 INFO-> 总计5个线程,共用时:4.925 s,执行总数:10,错误数:0,失败数:0INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/okay_test/long/data/5收藏和取消收藏20201230163524INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/okay_test/long/mark/收藏和取消收藏20201230163524INFO-> ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~>  {>  ① . "rt":2006,>  ① . "total":10,>  ① . "qps":2.491528802072952,>  ① . "failRate":0.0,>  ① . "threads":5,>  ① . "startTime":"2020-12-30 16:35:24",>  ① . "endTime":"2020-12-30 16:35:28",>  ① . "errorRate":0.0,>  ① . "executeTotal":10,>  ① . "mark":"收藏和取消收藏20201230163524",>  ① . "table":"">  }~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~INFO-> 
Process finished with exit code 0
复制代码


  • 简直完美!哈哈哈!!!



FunTester,非著名测试开发,文章记录学习和感悟,欢迎关注,交流成长。

FunTester 热文精选

发布于: 10 小时前阅读数: 8
用户头像

FunTester

关注

公众号:FunTester,650+原创,欢迎关注 2020.10.20 加入

Have Fun,Tester! 公众号FunTester,坚持原创文章的测试人。 FunTester测试框架作者,DCS_FunTester分布式性能测试框架作者。

评论

发布
暂无评论
性能测试中集合点和多阶段问题初探