开发一个网站系统报价,html查看器,站长工具国产2023,友情链接的作用大不大#x1f3af; 本文档详细介绍了如何使用Apache JMeter进行压力测试#xff0c;以评估预定接口在高并发场景下的性能表现。通过创建线程组模拟不同数量的用户并发请求#xff0c;利用CSV文件动态配置时间段ID和用户token#xff0c;确保了测试数据的真实性和有效性。文档中还… 本文档详细介绍了如何使用Apache JMeter进行压力测试以评估预定接口在高并发场景下的性能表现。通过创建线程组模拟不同数量的用户并发请求利用CSV文件动态配置时间段ID和用户token确保了测试数据的真实性和有效性。文档中还展示了如何设置JMeter的各项参数、添加HTTP请求头、查看结果树和聚合报告等操作步骤。最终通过一次针对4000用户并发的压测实例分析了样本数、响应时间、异常率及吞吐量等关键指标验证了系统的稳定性和可靠性。 ️ HelloDam/场快订场馆预定 SaaS 平台 文章目录 压力测试Jmeter介绍测试目标数据准备Jmeter如何进行操作Jmeter设置创建线程组创建 HTTP 请求添加请求头添加查看结果树、聚合报告动态参数给请求参数配置不同的时间段ID依赖CSV生成代码绑定CSV文件 配置不同的用户tokenCSV 生成绑定 CSV 文件 简单测试 正式压测测试环境内存预热压力测试Jmeter结构 压力测试
为了评估和测量接口在高负载情况下的性能表现。压力测试通常用于确定系统在预期的最大负载下的运行情况识别系统可能存在的性能瓶颈以及验证系统的稳定性和可靠性。压力测试对于确保应用程序能够支持特定数量的并发用户或操作至关重要。
Jmeter介绍
Apache JMeter 是一款开源的、基于Java的性能测试工具主要用于测试静态和动态资源如静态文件、Java Servlets、CGI脚本、数据库和其他基于Web的应用程序资源等的性能。它最初设计用于Web应用测试但后来扩展到其他测试领域。JMeter可以用来模拟大量用户并发访问目标服务以此来分析在不同负载条件下应用的性能表现。此外它支持多种协议和技术包括HTTP、HTTPS、FTP、SOAP、REST、LDAP、TCP、SMTP等极大地增强了其灵活性和适用范围。JMeter的一大优点是它能够以图形界面或命令行模式运行而且由于它是用Java编写的因此可以在任何安装了Java虚拟机的平台上使用具有很好的跨平台性。
官网https://jmeter.apache.org/下载地址https://jmeter.apache.org/download_jmeter.cgi
测试目标
测试时间段预定接口在不同并发用户下的吞吐量。
数据准备
为了让测试结果更加有参考性需要尽量模拟现实生活中的预定逻辑即肯定是有多个用户同时进行预定且预定的场馆、分区、时间段都可能不同。因此我们需要先模拟生成一些数据其中包括场馆、分区、时间段模板、时间段。最终需要传给Jmeter的数据有
可接受预定的不同时间段 id不同用户登录之后的 token
Jmeter如何进行操作
Jmeter设置
修改为白色外观 设置为简体中文方便操作如果你英语好当我没说哈哈哈 创建线程组
创建线程组是一个基础且关键的步骤。线程组主要用来模拟用户对服务器或应用程序发起请求的行为。具体来说它定义了虚拟用户的数目即线程数、这些用户将如何行动以及它们执行动作的时间安排如启动时间、持续时间和关闭时间。 初步设置如下参数后续在进行压力测试的时候可以从小到大调整线程数等参数
一个线程代表一个用户每个用户对不同时间段发起多次请求可以先从50个用户开始逐步增加到500或1000个用户观察接口的性能变化循环次数每个线程发请求的数量相当于一个用户发起多少次预定Ramp-Up时间设置为5秒表示这1000个线程会在5秒内均匀启动起来每个线程之间的启动间隔大约为 5/1000 秒 创建 HTTP 请求
预订接口如下
GetMapping(/v1/reserve)
public Result reserve(RequestParam(timePeriodId) Long timePeriodId) {OrderDO orderDO timePeriodService.reserve(timePeriodId);return Results.success(orderDO);
}这里需要设置服务所在IP、端口以及请求的接口路径。因为预定的时候需要指明是哪个时间段所以需要在参数中进行设置 添加请求头
由于用户在预定时间段的时候需要先从用户登录之后的 token 信息中获知用户是谁所以我们需要将 token 设置到请求头中 注意除了设置 token 之外还需要添加Content-type为application/json后端接口才能正常解析 json 数据 添加查看结果树、聚合报告
结果树用来查看请求的请求参数、响应结果聚合报告用来查看这些请求的统计信息 动态参数
因为我们需要模拟不同用户预定不同时间段的行为这期间用户、时间段都有多个因此我们不能写死 HTTP 请求中的请求参数而是需要使用动态参数从 CSV 文件中读取数据然后动态设置到不同的请求中
给请求参数配置不同的时间段ID
依赖
CSV导出直接写一个单元测试类即可首先引入测试相关的依赖
dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdscopetest/scope
/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope
/dependencyCSV生成代码
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vrs.domain.entity.TimePeriodDO;
import com.vrs.service.TimePeriodService;
import com.vrs.utils.TxtUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;import java.io.File;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.List;/*** 可预定时间段id CSV 导出** Author dam* create 2025/1/12 15:06*/
RunWith(SpringRunner.class)
ContextConfiguration(classes {VrsVenueApplication.class})
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ReserveTestCSVGenerateTest {Autowiredprivate TimePeriodService timePeriodService;/*** csv地址*/private final String csvPath Paths.get().toAbsolutePath().getParent().getParent() File.separator tmp File.separator 场馆预定时间段.csv;Testpublic void generate() throws Exception {StringBuilder stringBuilder new StringBuilder();QueryWrapperTimePeriodDO queryWrapper new QueryWrapper();// 只查询在今天和今天之后的可预订时间段queryWrapper.ge(period_date, LocalDate.now());ListTimePeriodDO timePeriodDOList timePeriodService.list(queryWrapper);for (TimePeriodDO timePeriodDO : timePeriodDOList) {stringBuilder.append(timePeriodDO.getId() \n);}TxtUtil.write(new File(csvPath), stringBuilder.toString(), utf-8);}
}通过下面的注解为基于Spring Boot的应用程序提供全面的测试支持包括依赖注入、应用上下文的配置以及Web环境的模拟等这样我们才可以注入TimePeriodService来进行查询数据库等操作
RunWith(SpringRunner.class)
ContextConfiguration(classes {VrsVenueApplication.class})
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)导出的CSV文件如下图所示 绑定CSV文件
最后一步是给请求绑定 CSV 文件 设置CSV文件路径 最后在请求的参数中使用通过表头列名来绑定数据使用方式为${列名} 配置不同的用户token
CSV 生成
import com.vrs.domain.entity.UserDO;
import com.vrs.service.UserService;
import com.vrs.utils.TxtUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;import java.io.File;
import java.nio.file.Paths;
import java.util.List;/*** 模拟用户数据生成** Author dam* create 2025/1/12 15:06*/
RunWith(SpringRunner.class)
ContextConfiguration(classes {VrsAdminApplication.class})
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserTokenCSVGenerateTest {Autowiredprivate UserService userService;/*** csv地址*/private final String csvPath Paths.get().toAbsolutePath().getParent().getParent() File.separator tmp File.separator 用户token.csv;Testpublic void generate() throws Exception {StringBuilder stringBuilder new StringBuilder();ListUserDO userDOList userService.list();for (UserDO userDO : userDOList) {// 登录并返回一个tokenstringBuilder.append(userService.handleLogin(userDO).getToken() \n);}TxtUtil.write(new File(csvPath), stringBuilder.toString(), utf-8);}
}绑定 CSV 文件 简单测试
完成上面的操作之后启动压力测试即可在查看结果树中可以看到每个请求是否成功响应结果是什么 接口错误的原因 在汇总报告中可以查看压力测试的统计数据例如接口调用时间的平均值、最小值、最大值吞吐量……这里异常那么高的原因是用户已经购买过相应时间段或者时间段已经售罄 正式压测
测试环境
【测试机器】
名称MacBook Pro 2023尺寸14英寸CPUm2 pro丐版芯片6个性能核心、4个能效核心内存16GB
【服务启动方式】
为了模拟真实分布式环境下的性能表现项目使用微服务方式启动
内存预热
为了在预定的时候可以快速查询首先对需要使用到缓存进行预热这里涉及的缓存有时间段信息、时间段库存、时间段位图
package com.vrs;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vrs.constant.RedisCacheConstant;
import com.vrs.domain.entity.PartitionDO;
import com.vrs.domain.entity.TimePeriodDO;
import com.vrs.service.PartitionService;
import com.vrs.service.TimePeriodService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;import java.time.LocalDate;
import java.util.List;/*** 时间段预定缓存预热** Author dam* create 2025/1/12 15:06*/
RunWith(SpringRunner.class)
ContextConfiguration(classes {VrsVenueApplication.class})
SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TimePeriodCacheLoadTest {Autowiredprivate TimePeriodService timePeriodService;Autowiredprivate PartitionService partitionService;Testpublic void generate() throws Exception {QueryWrapperTimePeriodDO queryWrapper new QueryWrapper();// 只查询在今天和今天之后的可预订时间段queryWrapper.ge(period_date, LocalDate.now());ListTimePeriodDO timePeriodDOList timePeriodService.list(queryWrapper);for (TimePeriodDO timePeriodDO : timePeriodDOList) {timePeriodService.getTimePeriodDOById(timePeriodDO.getId());PartitionDO partitionDO partitionService.getPartitionDOById(timePeriodDO.getPartitionId());// 首先检测空闲场号缓存有没有加载好没有的话进行加载timePeriodService.checkBitMapCache(String.format(RedisCacheConstant.VENUE_TIME_PERIOD_FREE_INDEX_BIT_MAP_KEY, timePeriodDO.getId()), timePeriodDO.getId(), partitionDO.getNum());// 其次检测时间段库存有没有加载好没有的话进行加载timePeriodService.getStockByTimePeriodId(timePeriodDO.getId());}}
}预热之后的缓存如下 压力测试
测试参数如下
线程数4000循环次数10Ramp-Up时间
即模拟4000个用户进行场馆预定每个用户分别发送20次预定请求线程在20秒内启动完成 测试结果如下 样本数量总共有40,000个样本这表示在测试期间进行了40,000次请求或操作。响应时间 平均值6036毫秒表示所有请求的平均响应时间。中位数6442毫秒表示50%的请求响应时间低于此值。90%百分位7155毫秒表示90%的请求响应时间低于此值。95%百分位7264毫秒表示95%的请求响应时间低于此值。99%百分位7482毫秒表示99%的请求响应时间低于此值。最小值2毫秒表示最快的请求响应时间。最大值26692毫秒表示最慢的请求响应时间。 异常率7.84%的请求出现了异常当然这里的异常是时间段售罄、时间段过期之类的。吞吐量508.3次请求/秒表示系统在测试期间每秒处理的请求数量。网络流量 接收速率284.68 KB/sec表示系统每秒接收的数据量。发送速率248.40 KB/sec表示系统每秒发送的数据量。
Jmeter结构