1.需求来源及目标
和三方对接过程中,发现三方调用会出现瞬时5000的并发,服务接口反应慢。原先是用php开发的,后面服务重构 使用go语言重构 对接服务接口。重构完成后 需要对接口重新测试,并且测试接口的最大并发数
2.压测前的准备
主要是auth接口的压测,先在本地使用python将接口调通;确保接口的功能是没问题的
3.测试参数的准备
post类型的接口,参数格式为:
{"app_key": "", "pid_scope": "", "school_unique_id": "", "school_name": "", "timestamp": "", "unique_id": "", "version": "", "sign": ""}
其中需要注意的3个参数(timestamp,unique_id,sign ),别的参数都是固定的
timestamp 必须是当前时间戳,使用jmeter提供的时间函数 ${__time(/1000,)}
unique_id 必须全局唯一 需要不重复,使用jmeter提供的随机函数 ${__RandomString(6,ABC123456789DFGZHJAHSabcdefghijklxyz,)}
sign 是需要进行md5加密的,原先不知道jmeter已经提供了各种加密算法,自己使用java编写自定义的jmeter函数来实现加密功能;后面在网上找了java代码的方式
4.压测脚本的准备
4.1 接口信息
JSR223 PreProcessor 前置处理器: 处理参数 将unique_id timestamp sign 放入系统环境变量中,在接口参数中引用
import org.apache.commons.codec.digest.DigestUtils; ${__setProperty(unique_id,${__RandomString(6,ABC123456789DFGZHJAHSabcdefghijklxyz,)},)} ${__setProperty(timestamp,${__time(/1000,)},)} String unique_id = props.get("unique_id"); String timestamp = props.get("timestamp"); log.info("*****************unique_id=" + unique_id); log.info("*****************timestamp=" + timestamp); String appkey = ""; String app_secret = ""; String pid_scope = ""; String school_name = ""; String school_unique_id = ""; String version = ""; String input = appkey+app_secret+pid_scope+school_name+school_unique_id+timestamp+unique_id+version; log.info("----------------input=="+ input); // 加密数据 String sign = DigestUtils.md5Hex(input); vars.put("unique_id",unique_id); vars.put("timestamp",timestamp); vars.put("sign", sign); password_md5 = vars.get("sign"); // log.info("----------------sign="+ sign);
结果断言:JSON断言, $.code == 200
4.2 knowledge_points_tree接口
接口参数pid是固定的几个,从csv文件中读取
设置CSV Data Set Config
4.3 设置后端监听器
需要搭建一个influxdb数据库环境 并创建数据库jmeter
搭建grafana环境,添加influxdb数据源
在非gui环境下执行可以实时查看 运行数据
5.编写自定义函数
package org.functions;
import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.functions.AbstractFunction;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
import java.util.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class nbapiToken extends AbstractFunction {
private String input;
// /** * 函数执行逻辑,自定义函数的核心逻辑,并返回经过处理后的内容 * @param previousResult * @param currentSampler * @return * @throws InvalidVariableException */
@Override
public String execute(SampleResult previousResult, Sampler currentSampler) {
String sign = "";
try {
// 创建一个MessageDigest实例,指定MD5算法
MessageDigest md = MessageDigest.getInstance("MD5");
// 对输入字符串进行摘要计算
System.out.println("----------------------*************************input="+this.input);
byte[] digest = md.digest(this.input.getBytes());
// 将字节数组转换为十六进制字符串
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b & 0xff));
}
sign = sb.toString();
System.out.println("----------------------*************************sign="+sign);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
System.err.println("there have a error!!");
}
return sign;
}
/**
* 设置函数接收参数值,接收JMeter界面用户传递过来的参数 * @param parameters * @throws InvalidVariableException
*/
@Override
public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {
//检查参数个数
checkParameterCount(parameters, 1, 2);
//获取参数
Object[] params = parameters.toArray();
CompoundVariable cvOperate = (CompoundVariable)params[0];
this.input = cvOperate.execute();
}
/**
* 函数名称 * @return
*/
@Override
public String getReferenceKey() {
return "__nbapitoken";
}
/**
* 函数参数描述,JMeter界面显示的参数说明 * @return
*/
@Override
public List<String> getArgumentDesc() {
List<String> desc = new LinkedList<String>();
desc.add("input");
return desc;
}
}
将打出来的jar包 放入jmeter的\lib\ext 路径下