依照领导要求区分了两种压测模式:固定次数压测和固定时间压测。此前一直沿用的都是固定次数,所以本次第二版剥离了固定次数的模式增加了固定时间的模式。
这是第一版:性能测试框架
第二版的threadbase代码如下:
package com.fun.base.constaint;import com.fun.frame.SourceCode;import java.util.concurrent.CountDownLatch;/*** 多线程任务基类,可单独使用*/public abstract class ThreadBase<T> extends SourceCode implements Runnable {/*** 计数锁* <p>* 会在concurrent类里面根据线程数自动设定* </p>*/CountDownLatch countDownLatch;/*** 用于设置访问资源*/public T t;protected ThreadBase() {super();}/*** groovy无法直接访问t,所以写了这个方法** @return*/public String getT() {return t.toString();}/*** 运行待测方法的之前的准备*/protected abstract void before();/*** 待测方法** @throws Exception*/protected abstract void doing() throws Exception;/*** 运行待测方法后的处理*/protected abstract void after();public void setCountDownLatch(CountDownLatch countDownLatch) {this.countDownLatch = countDownLatch;}}
余下是固定次数模式的压测虚拟类:
package com.fun.base.constaint;import com.fun.frame.excute.Concurrent;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.ArrayList;import java.util.List;import static com.fun.utils.Time.getTimeStamp;/*** 请求时间限制的多线程类,限制每个线程执行的次数** <p>* 通常在测试某项用例固定时间的场景下使用,可以提前终止测试用例* </p>** @param <T> 闭包参数传递使用,Groovy脚本会有一些兼容问题,部分对象需要tostring获取参数值*/public abstract class ThreadLimitTimes<T> extends ThreadBase {private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTimes.class);/*** 任务请求执行次数*/public int times;/*** 用于设置访问资源*/public T t;public ThreadLimitTimes(T t, int times) {this(times);this.t = t;}public ThreadLimitTimes(int times) {this();this.times = times;}protected ThreadLimitTimes() {super();}/*** groovy无法直接访问t,所以写了这个方法** @return*/public String getT() {return t.toString();}@Overridepublic void run() {try {before();List<Long> t = new ArrayList<>();long ss = getTimeStamp();for (int i = 0; i < times; i++) {long s = getTimeStamp();doing();long e = getTimeStamp();t.add(e - s);}long ee = getTimeStamp();logger.info("执行次数:{},总耗时:{}", times, ee - ss);Concurrent.allTimes.addAll(t);} catch (Exception e) {logger.warn("执行任务失败!", e);} finally {if (countDownLatch != null)countDownLatch.countDown();after();}}/*** 运行待测方法的之前的准备*/protected abstract void before();/*** 待测方法** @throws Exception*/protected abstract void doing() throws Exception;/*** 运行待测方法后的处理*/protected abstract void after();}
余下是固定时间模式虚拟类:
package com.fun.base.constaint;import com.fun.frame.excute.Concurrent;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.ArrayList;import java.util.List;import static com.fun.utils.Time.getTimeStamp;/*** 请求时间限制的多线程类,限制每个线程执行的时间* <p>* 通常在测试某项用例固定时间的场景下使用,可以提前终止测试用例* </p>** @param <T> 闭包参数传递使用,Groovy脚本会有一些兼容问题,部分对象需要tostring获取参数值*/public abstract class ThreadLimitTime<T> extends ThreadBase {/*** 全局的时间终止开关*/private static boolean key = false;private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTime.class);/*** 任务请求执行时间,单位是秒*/public int time;/*** 用于设置访问资源*/public T t;public ThreadLimitTime(T t, int time) {this(time);this.t = t;}public ThreadLimitTime(int time) {this();this.time = time * 1000;}protected ThreadLimitTime() {super();}@Overridepublic void run() {try {before();List<Long> t = new ArrayList<>();long ss = getTimeStamp();while (true) {long s = getTimeStamp();doing();long e = getTimeStamp();t.add(e - s);if ((e - ss) > time || key) break;}long ee = getTimeStamp();logger.info("执行时间:{} s,总耗时:{}", time / 1000, ee - ss);Concurrent.allTimes.addAll(t);} catch (Exception e) {logger.warn("执行任务失败!", e);} finally {if (countDownLatch != null)countDownLatch.countDown();after();}}/*** 用于在某些情况下提前终止测试*/public static void stopAllThread() {key = true;}}
这里我多加了一个终止测试的key,暂时没有用,以防万一。之所以没有采用另起线程去计时原因有二:进行测试过程中无论如何都会记录时间戳,多余的计算比较时间戳大小消耗性能很低,可以忽略;另起线程设计麻烦,在发生意外情况时缺少第二种保险措施。
下面是两种实现类的Demo,以HTTPrequestbase作为基础的多线程类。下面是固定次数模式的多线程类:
/*** http请求多线程类*/public class RequestThreadTimes extends ThreadLimitTimes {static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class);/*** 请求*/public HttpRequestBase request;/*** 单请求多线程多次任务构造方法** @param request 被执行的请求* @param times 每个线程运行的次数*/public RequestThreadTimes(HttpRequestBase request, int times) {this.request = request;this.times = times;}@Overridepublic void before() {GCThread.starts();}@Overrideprotected void doing() throws Exception {getResponse(request);}@Overrideprotected void after() {GCThread.stop();}/*** 多次执行某个请求,但是不记录日志,记录方法用 loglong* <p>此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配</p>** @param request 请求* @throws IOException*/void getResponse(HttpRequestBase request) throws IOException {CloseableHttpResponse response = ClientManage.httpsClient.execute(request);String content = FanLibrary.getContent(response);if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)logger.warn("响应状态码:{},响应内容:{}", content, response.getStatusLine());response.close();}}
下面是固定时间模式的多线程类:
package com.fun.frame.thead;import com.fun.base.constaint.ThreadLimitTime;import com.fun.frame.httpclient.ClientManage;import com.fun.frame.httpclient.FanLibrary;import com.fun.frame.httpclient.GCThread;import org.apache.http.HttpStatus;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpRequestBase;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.IOException;/*** http请求多线程类*/public class RequestThreadTime extends ThreadLimitTime {static Logger logger = LoggerFactory.getLogger(RequestThreadTime.class);/*** 请求*/public HttpRequestBase request;/*** 单请求多线程多次任务构造方法** @param request 被执行的请求* @param times 每个线程运行的次数*/public RequestThreadTime(HttpRequestBase request, int time) {this.request = request;this.time = time;}@Overridepublic void before() {GCThread.starts();}@Overrideprotected void doing() throws Exception {getResponse(request);}@Overrideprotected void after() {GCThread.stop();}/*** 多次执行某个请求,但是不记录日志,记录方法用 loglong* <p>此方法只适应与单个请求的重复请求,对于有业务联系的请求暂时不能适配</p>** @param request 请求* @throws IOException*/void getResponse(HttpRequestBase request) throws IOException {CloseableHttpResponse response = ClientManage.httpsClient.execute(request);String content = FanLibrary.getContent(response);if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)logger.warn("响应状态码:{},响应内容:{}", content, response.getStatusLine());response.close();}}
下面是使用Demo:
package com.fun;import com.fun.base.constaint.ThreadLimitTime;import com.fun.frame.SourceCode;import com.fun.frame.excute.Concurrent;import java.util.ArrayList;import java.util.List;public class AR extends SourceCode {public static void main(String[] args) {ThreadLimitTime<Object> threadLimitTime = new ThreadLimitTime<Object>(10) {/*** 运行待测方法的之前的准备*/@Overrideprotected void before() {}/*** 待测方法** @throws Exception*/@Overrideprotected void doing() throws Exception {AR.test();}/*** 运行待测方法后的处理*/@Overrideprotected void after() {}};new Concurrent(threadLimitTime,5).start();FanLibrary.testOver();}public static void test() {synchronized (AR.class) {sleep(100);output("fun");}}}
剩下的mysql和redis以及dubbo的Demo就不写了,各位看官看着发挥即可。
原文作者:FunTester;如有侵权,请联系管理员删除。