一、Apache JMeter
Apache JMeter是一个开源软件,100%纯Java应用程序,旨在负载测试功能行为和衡量性能。它最初是为测试Web应用程序而设计的,但后来扩展到了其他测试功能。
本文将用Jmeter对tomcat下的web应用进行压力测试。
二、使用Jmeter
1、在官网下载应用
2、执行bin目录下的jmeter.bat,打开GUI
3、创建 Plan -> 添加 Thread Group -> 添加 Http Request -> 执行测试计划 start -> 保存为jmx文件
4、创建Plan,添加线程组,配置线程数和持续时间(若配置持续10秒的200并发,则添加2000个线程,时间设置为10秒)
4、添加 Http Request,设置被测试的接口
5、若使用GUI界面进行测试,则可以根据需要添加lisener,如View Results Tree、Summary Report等(官方不推荐)
6、保存为jmx测试文件
7、命令行执行测试计划
# 生成jtl文件
jmeter -n -t D:\software\apache-jmeter-5.3\test_file\test1.jmx -l D:\software\apache-jmeter-5.3\test_file\v2\test.jtl
# jtl生成测试报告
jmeter -g D:\software\apache-jmeter-5.3\test_file\v1\test.jtl -e -o D:\software\apache-jmeter-5.3\test_file\v1\html
# 直接生成测试报告
jmeter -n -t D:\software\apache-jmeter-5.3\test_file\test1.jmx -l D:\software\apache-jmeter-5.3\test_file\v2\test.jtl -e -o D:\software\apache-jmeter-5.3\test_file\v2\html
如果命令报错:
Error generating the report: org.apache.jmeter.report.dashboard.GenerationException: Cannot assign “${jmeter.reportgenerator.apdex_satisfied_threshold}” to property “set_satisfied_threshold” (mapped as “setSatisfiedThreshold”), skip it … end of run
则修改user.perperties配置
jmeter.reportgenerator.apdex_satisfied_threshold=1500
jmeter.reportgenerator.apdex_tolerated_threshold=1500
然后在所有命令后指定配置文件
-p D:\software\apache-jmeter-5.3\bin\user.properties
三、批量接口测试
下面是一个自动化测试脚本,可以对多个接口进行不同并发的测试、减少人为干预因素
for %%i in (100,200,500,1000) do (
echo %%i concurrent start
md E:\temp\jmeter_test\c%%i\api1\html
md E:\temp\jmeter_test\c%%i\api2\html
md E:\temp\jmeter_test\c%%i\api3\html
md E:\temp\jmeter_test\c%%i\api4\html
ping -n 120 localhost >nul
call "D:\software\apache-jmeter-5.3\bin\jmeter" -n -t E:\temp\jmeter_test\plan\api1\test%%i.jmx -l E:\temp\jmeter_test\c%%i\api1\test.jtl -e -o E:\temp\jmeter_test\c%%i\api1\html -p D:\software\apache-jmeter-5.3\bin\user.properties
echo %%iapi1 test finish.
ping -n 60 localhost >nul
call "D:\software\apache-jmeter-5.3\bin\jmeter" -n -t E:\temp\jmeter_test\plan\api2\test%%i.jmx -l E:\temp\jmeter_test\c%%i\api2\test.jtl -e -o E:\temp\jmeter_test\c%%i\api2\html -p D:\software\apache-jmeter-5.3\bin\user.properties
echo %%iapi2 test finish.
ping -n 60 localhost >nul
call "D:\software\apache-jmeter-5.3\bin\jmeter" -n -t E:\temp\jmeter_test\plan\api3\test%%i.jmx -l E:\temp\jmeter_test\c%%i\api3\test.jtl -e -o E:\temp\jmeter_test\c%%i\api3\html -p D:\software\apache-jmeter-5.3\bin\user.properties
echo %%iapi3 test finish.
ping -n 60 localhost >nul
call "D:\software\apache-jmeter-5.3\bin\jmeter" -n -t E:\temp\jmeter_test\plan\api4\test%%i.jmx -l E:\temp\jmeter_test\c%%i\api4\test.jtl -e -o E:\temp\jmeter_test\c%%i\api4\html -p D:\software\apache-jmeter-5.3\bin\user.properties
echo %%iapi4 test finish.
)
echo "all finish!"
pause
得到测试报告后,可以执行下面程序来获取到所有的测试结果,这里的结果为markdown的表格
public class JmeterFileAnalysis {
public static final String PATH = "E:\\temp\\jmeter_test\\result";
// 数据行
public static final String REGEX_STATISTICS = "statisticsTable";
public static void main(String[] args) {
List<File> list = new ArrayList<>();
getMatchFiles(new File(PATH), list);
for (File file : list) {
System.out.println(file.getAbsolutePath());
try (FileReader reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader)) {
String line;
StringBuffer sb = null;
String tableName = null;
while ((line = br.readLine()) != null) {
if (line.contains(REGEX_STATISTICS)) {// 表名
// System.out.println(line);
System.out.println(resovleLine(line));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String getMatchContent(String content, String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
return matcher.group(1);
}
return "";
}
/**
* 获取所有包含数据的文件路径
* @param directory
* @param list
*/
public static void getMatchFiles(File directory, List<File> list) {
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
getMatchFiles(file, list);
} else {
if (file.getName().contains("dashboard.js")) {
list.add(file);
}
}
}
}
public static String m2(String num) {
BigDecimal bg = new BigDecimal(num);
return bg.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 处理包含数据的行、转化为md表格
* @param line
* @return
*/
public static String resovleLine(String line) {
String json = line.replace(" createTable($(\"#statisticsTable\"), ", "").replace(", function(index, item){", "");
JSONObject object = JSON.parseObject(json);
JSONArray titles = object.getJSONArray("titles");
JSONArray data = object.getJSONObject("overall").getJSONArray("data");
// System.out.println(titles);
// System.out.println(data);
StringBuffer sb = new StringBuffer();
titles.forEach(e -> {
sb.append(" | ").append(e.toString());
});
sb.append("| \r\n");
sb.append("| --------- | ----------- | --------- | --------- | --------- | --------- | --------- | --------- | ---- | ---- | ---- | ---- | ---- | ---- |\r\n");
data.forEach(e -> {
if (e.toString().contains(".")) {
}
String temp = e.toString().contains(".") ? m2(e.toString()) : e.toString();
sb.append(" | ").append(temp);
});
sb.append("| \r\n");
return sb.toString();
}
}
结果示例:
E:\temp\jmeter_test\result\c100\api1\html\content\js\dashboard.js
| Label | #Samples | KO | Error % | Average | Min | Max | Median | 90th pct | 95th pct | 99th pct | Transactions/s | Received | Sent|
| ——— | ———– | ——— | ——— | ——— | ——— | ——— | ——— | —- | —- | —- | —- | —- | —- |
| Total | 2000 | 0 | 0.00 | 512.77 | 5 | 5665 | 15.00 | 2074.00 | 3338.45 | 4911.91 | 100.49 | 271.34 | 115.31|
E:\temp\jmeter_test\result\c100\api2\html\content\js\dashboard.js
| Label | #Samples | KO | Error % | Average | Min | Max | Median | 90th pct | 95th pct | 99th pct | Transactions/s | Received | Sent|
| ——— | ———– | ——— | ——— | ——— | ——— | ——— | ——— | —- | —- | —- | —- | —- | —- |
| Total | 2000 | 0 | 0.00 | 9.12 | 3 | 81 | 6.00 | 18.00 | 27.00 | 51.99 | 100.35 | 98.48 | 62.62|
这样就可以快速得到所有的测试结果,方便比较
四、压测过程中程序的优化方向
1、tomcat内存优化(JVM参数)、线程优化(连接数、协议)
2、数据库连接池优化
3、mysql连接数、索引等(使用show processlist查看线程数)
五、使用JVisualVM监控服务器状态
JVisualVM是jdk自带的可视化监控工具,压测过程中我们可以通过它来监控程序的状态。
使用步骤:
- 1、修改tomcat的
catalina.sh
CATALINA_OPTS="-Djava.rmi.server.hostname=192.168.18.132 -Dcom.sun.management.jmxremote.port=1100 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
注:
-Dcom.sun.management.jmxremote.port :1100 这个是配置远程 connection 的端口号的,要确定这个端口没有被占用
-Dcom.sun.management.jmxremote.ssl=false 指定了 JMX 是否启用 ssl
-Dcom.sun.management.jmxremote.authenticate=false 指定了JMX 是否启用鉴权(需要用户名,密码鉴权)
前面是固定配置,是 JMX 的远程服务权限的
-Djava.rmi.server.hostname :这个是配置 server 的 IP 的
- 2、打开JVisualVM,添加对应远程连接