在之前的性能测试方案设计中,如果是涉及到多用户的,我一般都是通过先登录用户,然后再将Base
对象传入多线程任务类,以此进行性能测试。
但是这种处理方式有个问题,就是在执行多线程任务类之前,可能会造成等待时间过多,因为需要串行登录用户,如果线程过多的话,等待的时间会稍等长一点。
为此我找到了一个解决办法,就是使用线程同步类CyclicBarrier
将用户登录过程在多线程中实现,然后所有用户登录完成之后再进行性能测试方法的执行,简单讲就是设置一个多线程集合点,所有线程都到达集合点之后,再一起执行具体的测试方法。
之前的文章又介绍过多线程同步类CountDownLatch
、CyclicBarrier
和Phaser
,以及在我之前的性能测试过程中的应用,文章列表如下:
分两步:第一步记录一条数据(有唯一性验证);第二步更改该条记录的状态。
描述比较模糊,简单理解就是insert
之后update
,业务功能简单。
虽然业务简单,但是实现比较麻烦,所以我采取了链路性能测试,确定唯一性标记,然后进行update
,避免了,单独测试造数据太麻烦的问题。
伪代码如下:
@Override
protected void doing() {
String orderNum = "FunTester" + getMark() + StringUtil.getString(10)
threadmark += orderNum
order.insert(orderNum)
order.update(orderNum)
}
这里将orderNum
当做标记对象了,用于链路追踪和日志查询。
我继续采取ThreadLimitTimesCount<Integer>
类作为模型类的内部静态类实现,定长线程和固定次数。
private static class FunTester extends ThreadLimitTimesCount<Integer> {
Order order
CyclicBarrier cyclicBarrier
FunTester(int u, int times, CyclicBarrier cyclicBarrier) {
super(u, times, null)
this.cyclicBarrier = cyclicBarrier
}
@Override
void before() {
super.before()
this.order = new Order(getBase(t))
cyclicBarrier.await()
}
@Override
protected void doing() {
String orderNum = "f" + getMark() + StringUtil.getString(5)
threadmark += orderNum
order.create(101, "FunTester测试课程", 13120454219, 10, 10, orderNum)
order.refund(orderNum)
}
}
这里用到了cyclicBarrier.await()
方法,使得所有线程达到该集合点之后,才进行下一步的代码执行。
static void main(String[] args) {
Common.notPrintResponse()
ClientManage.init(10, 5, 0, EMPTY, 0)
def argsUtil = new ArgsUtil(args)
def thread = argsUtil.getIntOrdefault(0, 10)
def times = argsUtil.getIntOrdefault(1, 10)
def threads = []
CyclicBarrier cyclicBarrier = new CyclicBarrier(thread, new Runnable() {
@Override
void run() {
logger.info("所有账号登录完成!,即将开始测试!")
}
})
thread.times {
threads << new FunTester(it, times, cyclicBarrier)
}
new Concurrent(threads, "一个不可描述的用例场景").start()
FunLibrary.testOver()
}
Common.notPrintResponse()
方法为了屏蔽测试过程中,打印响应结果,因为日志太多了,处理起来比较麻烦。最近在研究链路测试中对各个接口的数据处理,所以想到了这个方法。
INFO-> 当前用户:fv,IP:10.60.193.37,工作目录:/Users/fv/Documents/workspace/qa/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 本校共有:627名老师,852名学生,11个班级!
INFO-> 请求uri:不可描述的地址/login,耗时:458 ms, requestId:Fun20210310111251QvEl
INFO-> 请求uri:不可描述的地址/login,耗时:458 ms, requestId:Fun20210310111251xQKM
INFO-> 用户:82951571527,登录成功!
INFO-> 用户:82951571522,登录成功!
INFO-> 请求uri:不可描述的地址/login,耗时:458 ms, requestId:Fun20210310111251TLml
INFO-> 用户:82951571529,登录成功!
INFO-> 请求uri:不可描述的地址/login,耗时:471 ms, requestId:Fun20210310111251CgTd
INFO-> 用户:82951571531,登录成功!
INFO-> 请求uri:不可描述的地址/login,耗时:483 ms, requestId:Fun20210310111251YQyQ
INFO-> 请求uri:不可描述的地址/login,耗时:459 ms, requestId:Fun20210310111251IGUs
INFO-> 请求uri:不可描述的地址/login,耗时:458 ms, requestId:Fun20210310111251NZQt
INFO-> 请求uri:不可描述的地址/login,耗时:484 ms, requestId:Fun20210310111251KVRP
INFO-> 用户:82951571525,登录成功!
INFO-> 用户:82951571513,登录成功!
INFO-> 用户:82951571514,登录成功!
INFO-> 用户:82951571516,登录成功!
INFO-> 请求uri:不可描述的地址/login,耗时:604 ms, requestId:Fun20210310111251AXdV
INFO-> 用户:82951571518,登录成功!
INFO-> 请求uri:不可描述的地址/login,耗时:610 ms, requestId:Fun20210310111251KUMm
INFO-> 用户:82951571524,登录成功!
INFO-> 所有账号登录完成!,即将开始测试!
*********中间省略N次请求日志*************
INFO-> 线程:一个不可描述的用例场景2,执行次数:10,错误次数: 0,总耗时:2.317 s
INFO-> 一个不可描述的用例场景进度:▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍▍ 100%
INFO-> 总计10个线程,共用时:3.132 s,执行总数:100,错误数:0,失败数:0
INFO-> 数据保存成功!文件名:/Users/fv/Documents/workspace/qa/long/data/易视腾3.3购买退款101112_10
INFO->
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
> {
> ① . "rt":210,
> ① . "total":100,
> ① . "qps":47.619,
> ① . "failRate":0.0,
> ① . "threads":10,
> ① . "startTime":"2021-03-10 11:12:51",
> ① . "endTime":"2021-03-10 11:12:54",
> ① . "errorRate":0.0,
> ① . "executeTotal":100,
> ① . "mark":"一个不可描述的用例场景101112",
> ① . "table":"eJwBHQDi/+aVsOaNrumHj+WkquWwkSzml6Dms5Xnu5jlm74hMCkTtQ=="
> }
~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~ JSON ~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~~☢~
INFO-> 数据量太少,无法绘图!
最后因为测试请求,数据量太少了,所以屏蔽了画图功能,欲知图像如何,请参考:性能测试中图形化输出测试数据。