ITPub博客

首页 > 数据库 > 数据库开发技术 > 性能测试框架第二版

性能测试框架第二版

原创 数据库开发技术 作者:FunTester 时间:2019-12-04 10:07:18 0 删除 编辑

依照领导要求区分了两种压测模式:固定次数压测和固定时间压测。此前一直沿用的都是固定次数,所以本次第二版剥离了固定次数的模式增加了固定时间的模式。

这是第一版:性能测试框架

第二版的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(); }
@Override public 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(); }
@Override public 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; }
@Override public void before() { GCThread.starts(); }
@Override protected void doing() throws Exception { getResponse(request); }
@Override protected 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; }
@Override public void before() { GCThread.starts(); }
@Override protected void doing() throws Exception { getResponse(request); }
@Override protected 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(); }}
  • 其中可以发现,差别就在于属性time还是times的设定。

下面是使用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) { /** * 运行待测方法的之前的准备 */ @Override protected void before() {
}
/** * 待测方法 * * @throws Exception */ @Override protected void doing() throws Exception { AR.test(); }
/** * 运行待测方法后的处理 */ @Override protected 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;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-07-07

  • 博文量
    1037
  • 访问量
    420813