Jmeter 动态参数压力测试时间段预定接口
🎯 本文档详细介绍了如何使用Apache JMeter进行压力测试,以评估预定接口在高并发场景下的性能表现。通过创建线程组模拟不同数量的用户并发请求,利用CSV文件动态配置时间段ID和用户token,确保了测试数据的真实性和有效性。文档中还展示了如何设置JMeter的各项参数、添加HTTP请求头、查看结果树和聚合报告等操作步骤。最终,通过一次针对4000用户并发的压测实例,分析了样本数、响应时间、异常率及吞吐量等关键指标,验证了系统的稳定性和可靠性。
🏠️ HelloDam/场快订(场馆预定 SaaS 平台)
文章目录
- 压力测试
- Jmeter介绍
- 测试目标
- 数据准备
- Jmeter如何进行操作
- Jmeter设置
- 创建线程组
- 创建 HTTP 请求
- 添加请求头
- 添加查看结果树、聚合报告
- 动态参数
- 给请求参数配置不同的时间段ID
- 依赖
- CSV生成代码
- 绑定CSV文件
- 配置不同的用户token
- CSV 生成
- 绑定 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导出直接写一个单元测试类即可,首先引入测试相关的依赖
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
CSV生成代码
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();QueryWrapper<TimePeriodDO> queryWrapper = new QueryWrapper<>();// 只查询在今天和今天之后的可预订时间段queryWrapper.ge("period_date", LocalDate.now());List<TimePeriodDO> 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();List<UserDO> 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英寸
- CPU:m2 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 {QueryWrapper<TimePeriodDO> queryWrapper = new QueryWrapper<>();// 只查询在今天和今天之后的可预订时间段queryWrapper.ge("period_date", LocalDate.now());List<TimePeriodDO> 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
- 循环次数:10
- Ramp-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结构

相关文章:
Jmeter 动态参数压力测试时间段预定接口
🎯 本文档详细介绍了如何使用Apache JMeter进行压力测试,以评估预定接口在高并发场景下的性能表现。通过创建线程组模拟不同数量的用户并发请求,利用CSV文件动态配置时间段ID和用户token,确保了测试数据的真实性和有效性。文档中还…...
超大型集团合并报表数智管理转型
摘要:数字经济时代,数字化技术已成为驱动财务管理价值释放的重要引擎,数智化能力的提升是当前一流财务信息化建设的最新趋势。财务部门是企业的“数据交汇中心”和“信息加工中心”,通过对企业各项财务数据的分类、汇总和清晰呈现…...
[MCAL]Mcu配置
PostBuild: PreCompile: 选择时钟来源; 选择初始McuInitClock() 函数 电路手册里有晶振频率,如上所示;...
Qt基础项目篇——Qt版Word字处理软件
一、核心功能 本软件为多文档型程序,界面是标准的 Windows 主从窗口 拥有:主菜单、工具栏、文档显示区 和 状态栏。 所要实现的东西,均在下图了。 开发该软件,主要分为下面三个阶段 1)界面设计开发 多窗口 MDI 程序…...
算法刷题笔记——图论篇
这里写目录标题 理论基础图的基本概念图的种类度 连通性连通图强连通图连通分量强连通分量 图的构造邻接矩阵邻接表 图的遍历方式 深度优先搜索理论基础dfs 与 bfs 区别dfs 搜索过程深搜三部曲所有可达路径广度优先搜索理论基础广搜的使用场景广搜的过程 岛屿数量孤岛的总面积沉…...
Java空指针异常处理:判空、Optional与Assert解析
在Java编程中,空指针异常(NullPointerException)是最常见的运行时错误之一。本文将深入探讨三种处理空指针异常的方法:传统的判空检查、Java 8引入的Optional类以及使用断言(Assert)。通过代码示例和应用场…...
【vim】vim编辑器如何设置行号
vim编辑器如何设置行号 一、**临时设置行号**二、永久设置行号2.1. **用户配置文件方式(针对当前用户)**2.2. **全局配置文件方式(谨慎使用,会影响所有用户)** 在Vim中设置行号有以下两种常见的方法: 一、…...
MySQL可直接使用的查询表的列信息
文章目录 背景实现方案模板SQL如何查询列如何转大写如何获取字符位置如何拼接字段 SQL适用场景 背景 最近产品找来,想让帮忙出下表的信息,字段驼峰展示,每张表信息show create table全部展示,再逐个粘贴,有点太耗费时…...
在线宠物用品|基于vue的在线宠物用品交易网站(源码+数据库+文档)
|在线宠物用品交易网站 目录 基于springbootvue的在线宠物用品交易网站 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布道师&am…...
《安富莱嵌入式周报》第349期:VSCode正式支持Matlab调试,DIY录音室级麦克风,开源流体吊坠,物联网在军工领域的应用,Unicode字符压缩解压
周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版: 《安富莱嵌入式周报》第349期:VSCode正式支持Matlab调试,DIY录音室级麦克风…...
使用LabVIEW的History功能实现队列数据的读取而不清空
在LabVIEW中,有多种方法可以读取队列中的数据而不清空它。使用 Dequeue Element 和 Enqueue Element 函数可以实现读取并重新插入数据回队列,但当需要处理大数据流或需要更动态的解决方案时,这种方法可能会变得繁琐。一个更高效的解决方案是利…...
电脑如何访问手机文件?
手机和电脑已经深深融入了我们的日常生活,无时无刻不在为我们提供服务。除了电脑远程操控电脑外,我们还可以在电脑上轻松地访问Android或iPhone手机上的文件。那么,如何使用电脑远程访问手机上的文件呢? 如何使用电脑访问手机文件…...
SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用
SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用 文章目录 SpringBoot实现定时任务,使用自带的定时任务以及调度框架quartz的配置使用一. 使用SpringBoot自带的定时任务(适用于小型应用)二. 使用调度框架…...
java上传图片功能实现
1 MinIO核心概念 下面介绍MinIO中的几个核心概念,这些概念在所有的对象存储服务中也都是通用的。 对象(Object) 对象是实际的数据单元,例如我们上传的一个图片。 存储桶(Bucket) 存储桶是用于组织对象的命…...
73,【5】BUUCTF WEB [网鼎杯 2020 玄武组]SSRFMe(未解出)
进入靶场 又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码又是代码 <?php // 检查 URL 是否为内部 IP 地址 function check_inner_ip($url) {// 使用正则表达式检查 URL 格式是否以 http、https、gopher 或 d…...
【FreeRTOS 教程 一】任务结构体及其基础创建使用
目录 一、任务与协程的区别: (1)任务的特点: (2)协程的特点: (3)总结: 二、任务概述 : (1)任务状态: &…...
深入剖析 JVM 内存模型
前言: 下面分别介绍了新生代和老年代的不同收集器及其相关子类型,并附有示例代码和说明,感兴趣的朋友可以参考一下。 简介: 在 Java 虚拟机(JVM)的世界里,内存模型是其核心架构之一࿰…...
解决DeepSeek-R1模型在Cursor中使用报错的问题
在使用Cursor时,如果你尝试调用DeepSeek-R1模型,可能会遇到以下报错信息: {"error": {"message": "deepseek-reasoner does not support successive user or assistant messages (messages[1] and messages[2] in …...
ASP.NET Core 6.0 如何处理丢失的 Startup.cs 文件
介绍 .NET 6.0 已经发布,ASP.NET Core 6.0 也已发布。其中有不少变化让很多人感到困惑。例如,“谁动了我的奶酪”,它在哪里Startup.cs?在这篇文章中,我将深入研究这个问题,看看它移动到了哪里以及其他变化。…...
Java如何向http/https接口发出请求
用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一个工具类 import javax.net.ssl.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Outpu…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
