利用微基准测试修正压测结果
前段时间做了一次参数需要签名的接口性能测试,有文为证:线程安全类在性能测试中应用。在处理测试结果时候遇到一个问题:因为本机签名耗时较多,10ms级别,并发情况能达到100ms级别。所以进行数据校验尤为重要。
在两次请求间歇,本地只是做了测试结果的收集,测试数据的生成和签名,其中签名是最耗时的。这个时候在收集完测试数据之后,就需要进行一轮甚至几轮的微基准测试。
微基准测试用来测量微小代码单元的性能,包括调用同步方法的用时与非同步方法的用时比较,创建线程的代价与使用线程池的代价,执行某种算法的耗时与其替代实现的耗时,等等。
下面是我组装参数和参数签名方法,注释掉请求和处理相应的方法之后:
@Overrideprotectedvoid doing() throws Exception {
String url = com.okayqa.studentapd.base.OkayBase.HOST + "/api/member/createOrRenewMember"
Map<String, String> p = new HashMap<>();
p.put("days", "1");
p.put("memberId", "208");
p.put("orderNo", "F" + RString.getString(4) + i.getAndAdd(1));
p.put("orderPaySystemId", "85123213");
p.put("orderPayTime", "2020-02-09 10:00:00");
p.put("payMoney", "30");
p.put("recordSources", "3");
p.put("renewal", "false");
def user = Users.getStuUser(i.getAndAdd(1) % 1000)
// output(user)
p.put("systemId", user);
String sign = RSAUtilLJT.sign(p, RSAUtilLJT.getPrivateKey(RSAUtilLJT.RSA_PRIVATE_KEY));
p.put("sign", sign);
HttpPost post = getHttpPost(url, JSON.toJSONString(p));
def s = "F" + getNanoMark()
// post.addHeader(getHeader("requestid", s)); def simlple = FanLibrary.excuteSimlple(post)// if (!simlple.contains("success")) {// logger.warn(s + OR + user + simlple.toString())// fail()// }
}
```
这样再运行接口压测脚本:
```Groovy
publicstaticvoid main(String[] args) {
def argsUtil = new ArgsUtil(args)
def thread = argsUtil.getIntOrdefault(0, 1)
def times = argsUtil.getIntOrdefault(1, 100)
def reqs = []
thread.times {
// def mark = new HeaderMark("requestid")
reqs << new Thr(times)
}
new Concurrent(reqs, "会员支付和续费接口").start()
testOver()
}
用同样的线程和次数来测试非请求消耗的时间,然后再从接口性能测试时间中减去这块时间就好了。这样做还有一个问题:经过数据校准后的吞吐量应该是高于实际值的,因为本机请求间隙相当于进行了等待,实际服务器承受的压测并不是修正后的数据。关于这一点,我将在下一期文章分享如何减少本机误差。
性能测试如何减少本机误差
在接口测试过程中,某个线程连续两次请求中间都会消耗的时间,线程在收到响应进行第二次请求的时候会消耗一些时间,比如进行结果验证,日志存储,或者进行数据统计等等。(1140267353)一起成长一起加油的伙伴群!软件测试,与你同行!
一般来讲这些时间都是微秒级别的,偶尔会遇到一些毫秒级别的,比如这次:线程安全类在性能测试中应用,中间参数签名的消耗时间在10ms级别,如果在并发的情况下甚至达到100ms,而且对本机的CPU资源消耗也比较厉害。
解决办法: 提前将数据签名,以空间换时间,先把所有的参数签名完毕,然后再去发送请求。
中间用到了线程安全的队列LinkedBlockingDeque
,这个可以帮助我们解决掉数据可能会重复的问题。
新版发代码如下:
package com.okayqa.others.payyst
import com.alibaba.fastjson.JSON
import com.fun.base.constaint.ThreadLimitTimesCount
import com.fun.frame.excute.Concurrent
import com.fun.frame.httpclient.FanLibrary
import com.fun.utils.ArgsUtil
import com.fun.utils.RString
import com.okayqa.common.RSAUtilLJT
import com.okayqa.common.Users
import org.apache.http.client.methods.HttpPost
import org.slf4j.Logger
import java.util.concurrent.LinkedBlockingDeque
import java.util.concurrent.atomic.AtomicInteger
class T extends FanLibrary {static Logger logger = getLogger(T.class)
static LinkedBlockingDeque<Map<String, String>> ppp = new LinkedBlockingDeque<>()
static AtomicInteger i = new AtomicInteger(111000);
publicstaticvoid main(String[] args) {
def argsUtil = new ArgsUtil(args)
def thread = argsUtil.getIntOrdefault(0, 1)
def times = argsUtil.getIntOrdefault(1, 100)
def ps = []
thread.times {
// def mark = new HeaderMark("requestid")
ps << new Thr(times)
}
new Concurrent(ps, "参数提前初始化").start()
def reqs = []
thread.times {
// def mark = new HeaderMark("requestid")
reqs << new Thr(times)
}
new Concurrent(reqs, "会员支付和续费接口").start()
testOver()
}
publicstatic Map<String, String> getParams() {
def add = i.getAndAdd(1)
Map<String, String> p = new HashMap<>();
p.put("days", "1");
p.put("memberId", "208");
p.put("orderNo", "F" + RString.getString(4) + add);
p.put("orderPaySystemId", "85123213");
p.put("orderPayTime", "2020-02-09 10:00:00");
p.put("payMoney", "30");
p.put("recordSources", "3");
p.put("renewal", "false");
def user = Users.getStuUser(add % 1000)
p.put("systemId", user);
String sign = RSAUtilLJT.sign(p, RSAUtilLJT.getPrivateKey(RSAUtilLJT.RSA_PRIVATE_KEY));
p.put("sign", sign);
return p;
}
staticclass P extends ThreadLimitTimesCount {public P(int times) {
super(null, times, null);
}
@Overrideprotectedvoid doing() throws Exception {
def add = i.getAndAdd(1)
Map<String, String> p = new HashMap<>();
p.put("days", "1");
p.put("memberId", "208");
p.put("orderNo", "F" + RString.getString(4) + add);
p.put("orderPaySystemId", "85123213");
p.put("orderPayTime", "2020-02-09 10:00:00");
p.put("payMoney", "30");
p.put("recordSources", "3");
p.put("renewal", "false");
def user = Users.getStuUser(add % 1000)
p.put("systemId", user);
String sign = RSAUtilLJT.sign(p, RSAUtilLJT.getPrivateKey(RSAUtilLJT.RSA_PRIVATE_KEY));
p.put("sign", sign);
ppp.add(p)
}
}
staticclass Thr extends ThreadLimitTimesCount {static Logger logger = getLogger(Thr.class)
public Thr(int times) {
super(null, times, null);
}
@Overrideprotectedvoid doing() throws Exception {
String url = com.okayqa.studentapd.base.OkayBase.HOST + "/api/member/createOrRenewMember"
HttpPost post = getHttpPost(url, JSON.toJSONString(ppp.take()));
def s = "F" + getNanoMark()
post.addHeader(getHeader("requestid", s));
def simlple = FanLibrary.excuteSimlple(post)
if (!simlple.contains("success")) {
logger.warn(s + OR + user + simlple.toString())
fail()
}
}
}
}
经过上文:利用微基准测试修正压测结果验证方法,稳稳的OK。
俺叫小枫,一个成天想着一夜暴富的测试员
(1140267353)一起成长一起加油的伙伴群!软件测试,与你同行!
群内可领取最新软件测试大厂面试资料和Python自动化、接口、框架搭建学习资料!
点赞关注不迷路!!!【三连ღ】,有问题也可私聊哟~(*╹▽╹*)