JMeter插件 Arrivals Thread Group 源码解析:实现原理与性能测试中的应用

Apache JMeter 是一款强大的性能测试工具,广泛应用于负载测试、压力测试和性能分析。为了满足不同场景的需求,JMeter 提供了丰富的插件生态系统。其中,Arrivals Thread Group 是一个非常有用的插件,它允许测试人员模拟更真实的用户行为,特别是在需要控制每秒到达用户数(RPS)的场景中。本文将深入分析 Arrivals Thread Group 的源码,探讨其实现原理,并展示如何在实际性能测试中应用该插件。


1. Arrivals Thread Group 简介

Arrivals Thread Group 是 JMeter 的一个第三方插件,由 Blazemeter 开发并维护。它的主要功能是根据设定的目标 RPS(每秒请求数)动态调整线程数,从而更精确地模拟用户行为。与传统的线程组(如 Thread Group)相比,Arrivals Thread Group 更适合需要控制请求速率的场景。

1.1 与传统线程组的对比

特性普通线程组Stepping Thread GroupArrivals Thread Group
负载模式固定线程数阶梯式增加线程数基于到达率动态调整线程数
用户行为模拟并发用户模型线性增长模型真实用户到达模型(泊松分布)
适用场景简单压力测试容量规划测试流量突发/稳定性测试
资源消耗中等低(智能调度)

1.2 主要特点:

  • 动态线程调整:根据目标 RPS 自动调整并发线程数。
  • 平滑负载:避免传统线程组中因固定线程数导致的负载波动。
  • 更真实的用户行为:模拟用户到达系统的真实模式。

2. Arrivals Thread Group 源码分析

2.1 源码结构

Arrivals Thread Group 的源码主要包括以下几个核心类:

  • ArrivalsThreadGroup:线程组的实现类,负责管理线程的创建和调度。
  • ArrivalsThreadGroupGui:线程组的 GUI 类,提供用户界面配置。

2.2 核心类解析

2.2.1 ArrivalsThreadGroup

ArrivalsThreadGroupAbstractDynamicThreadGroup 的子类,位于 com.blazemeter.jmeter.threads.arrivals 包中。它的主要功能是:

  • 动态调整线程数:根据目标 RPS 和系统响应时间,动态增加或减少线程数。
  • 线程池管理:通过线程池(poolThreads)管理空闲线程,优化资源利用率。
  • 统计信息记录:记录到达数(arrivals)、完成数(completions)和放弃数(abandons)等关键指标。
2.2.1.1 核心属性分析

ArrivalsThreadGroup 类中定义了多个关键属性,用于管理线程状态和统计信息:

  • arrivalsCount:记录到达的请求数(AtomicLong 类型,线程安全)。
  • completionsCount:记录完成的请求数(AtomicLong 类型,线程安全)。
  • abandonsCount:记录放弃的请求数(AtomicLong 类型,线程安全)。
  • poolThreads:管理空闲线程的集合(Set<DynamicThread> 类型,线程安全)。
2.2.1.2 核心方法分析
2.2.1.2.1 start() 方法

start() 方法是线程组的入口点,负责初始化线程组并启动线程调度器。

@Override
public void start(int groupIndex, ListenerNotifier listenerNotifier, ListedHashTree testTree, StandardJMeterEngine engine) {super.start(groupIndex, listenerNotifier, testTree, engine);synchronized (this) {try {wait(); // 等待第一个到达的请求log.info("Got first arrival");} catch (InterruptedException e) {log.warn("Interrupted start", e);}}
}
  • 功能:启动线程组,并等待第一个请求到达。
  • 关键点:通过 wait() 方法实现线程同步,确保线程组在第一个请求到达后才继续执行。
2.2.1.2.2 addThread() 方法

addThread() 方法用于向线程组中添加新线程。

@Override
public void addThread(DynamicThread threadWorker) {super.addThread(threadWorker);JMeterContextService.addTotalThreads(1); // 更新全局线程数
}
  • 功能:将新线程添加到线程组中,并更新全局线程数。
  • 关键点:通过 JMeterContextService.addTotalThreads(1) 确保线程数的全局一致性。
2.2.1.2.3 movedToPool() 方法

movedToPool() 方法用于将空闲线程移动到线程池中。

public boolean movedToPool(DynamicThread thread) {threads.remove(thread);if (thread.isStopping()) {log.debug("Did not move into pool, because thread is stopping: " + thread);return false;}poolThreads.add(thread); // 将线程添加到线程池log.debug("Moved thread to pool: " + thread + ", pool size: " + poolThreads.size());ThreadCountsAccessor.decrNumberOfThreads(); // 减少活跃线程数synchronized (thread) {try {thread.wait(); // 等待线程被唤醒} catch (InterruptedException e) {log.debug("Interrupted", e);}}ThreadCountsAccessor.incrNumberOfThreads(); // 增加活跃线程数return running;
}
  • 功能:将空闲线程移动到线程池中,并等待其被重新唤醒。
  • 关键点:通过 thread.wait() 实现线程的挂起,避免资源浪费。
2.2.1.2.4 releasedPoolThread() 方法

releasedPoolThread() 方法用于从线程池中释放线程。

public synchronized boolean releasedPoolThread() {if (poolThreads.isEmpty()) {return false;}DynamicThread thread = poolThreads.toArray(new DynamicThread[poolThreads.size()])[0];poolThreads.remove(thread);threads.add(thread); // 将线程重新加入活跃线程集合log.debug("Releasing pool thread: " + thread + ", pool size: " + poolThreads.size());synchronized (thread) {thread.notify(); // 唤醒线程}return true;
}
  • 功能:从线程池中释放线程,并将其重新加入活跃线程集合。
  • 关键点:通过 thread.notify() 唤醒挂起的线程。
2.2.1.2.5 isLimitReached() 方法

isLimitReached() 方法用于检查是否达到到达数限制。

public boolean isLimitReached() {long limit;try {limit = Long.parseLong(getArrivalsLimit());} catch (NumberFormatException e) {log.error("Invalid arrivals limit, defaulting to 0");limit = 0;}return !(limit <= 0 || arrivalsCount.longValue() < limit);
}
  • 功能:根据配置的到达数限制,判断是否达到限制。
  • 关键点:通过 arrivalsCount 记录当前到达数,并与配置的限制进行比较。
2.2.1.2.6 arrivalFact() 方法

arrivalFact() 方法用于记录到达事件。

public synchronized void arrivalFact(JMeterThread thread, long arrivalID) {arrivalsCount.incrementAndGet(); // 增加到达数notifyAll(); // 唤醒等待的线程saveLogRecord("ARRIVAL", thread.getThreadName(), thread.getThreadNum() + "." + arrivalID);
}
  • 功能:记录到达事件,并唤醒等待的线程。
  • 关键点:通过 notifyAll() 实现线程同步。
2.2.2 ArrivalsThreadGroupGui

ArrivalsThreadGroupGuiAbstractDynamicThreadGroupGui 的子类,位于 com.blazemeter.jmeter.threads.arrivals 包中。它的主要功能是:

  • 提供用户界面:允许用户配置目标 RPS、Ramp-Up 时间、Hold 时间等参数。
  • 数据绑定:将用户输入的配置数据绑定到 ArrivalsThreadGroup 对象。
  • 可视化预览:通过图表展示负载模式,帮助用户直观理解测试计划。
2.2.2.1 核心属性与方法分析
2.2.2.1.1 构造方法

ArrivalsThreadGroupGui 的构造方法用于初始化 GUI 组件,并添加帮助链接。

public ArrivalsThreadGroupGui() {super();JMeterPluginsUtils.addHelpLinkToPanel(this, getClass().getSimpleName());
}
  • 功能:初始化 GUI 组件,并添加帮助链接。
  • 关键点:通过 JMeterPluginsUtils.addHelpLinkToPanel 提供用户帮助文档的链接。
2.2.2.1.2 getLabelResource() 方法

getLabelResource() 方法用于返回 GUI 的标签资源。

@Override
public String getLabelResource() {return getClass().getCanonicalName();
}
  • 功能:返回 GUI 的标签资源,通常用于国际化支持。
  • 关键点:返回类的全限定名作为标签资源。
2.2.2.1.3 getStaticLabel() 方法

getStaticLabel() 方法用于返回 GUI 的静态标签。

@Override
public String getStaticLabel() {return "bzm - Arrivals Thread Group";
}
  • 功能:返回 GUI 的静态标签,显示在 JMeter 的界面中。
  • 关键点:标签名称为 bzm - Arrivals Thread Group,用于标识该线程组。
2.2.2.1.4 createThreadGroupObject() 方法

createThreadGroupObject() 方法用于创建 ArrivalsThreadGroup 对象。

protected ArrivalsThreadGroup createThreadGroupObject() {return new ArrivalsThreadGroup();
}
  • 功能:创建 ArrivalsThreadGroup 对象,用于存储用户配置。
  • 关键点:返回一个新的 ArrivalsThreadGroup 实例。
2.2.2.1.5 getAdditionalFieldsPanel() 方法

getAdditionalFieldsPanel() 方法用于获取额外的配置面板。

@Override
protected AdditionalFieldsPanel getAdditionalFieldsPanel() {return new AdditionalFieldsPanel(true);
}
  • 功能:返回一个额外的配置面板,用于设置高级参数。
  • 关键点:通过 AdditionalFieldsPanel 提供额外的配置选项。
2.2.2.1.6 setChartPropertiesFromTG() 方法

setChartPropertiesFromTG() 方法用于设置图表的属性。

@Override
protected void setChartPropertiesFromTG(AbstractDynamicThreadGroup tg) {if (tg instanceof ArrivalsThreadGroup) {ArrivalsThreadGroup atg = (ArrivalsThreadGroup) tg;previewChart.setYAxisLabel("Number of arrivals/" + atg.getUnitStr());}
}
  • 功能:根据 ArrivalsThreadGroup 的属性设置图表的 Y 轴标签。
  • 关键点:通过 previewChart.setYAxisLabel 设置图表的 Y 轴标签。
2.2.2.1.7 getRowColor() 方法

getRowColor() 方法用于返回图表的行颜色。

@Override
protected Color getRowColor() {return Color.MAGENTA;
}
  • 功能:返回图表的行颜色,用于区分不同的线程组。
  • 关键点:返回 Color.MAGENTA 作为行颜色。
2.2.2.1.8 getRowLabel() 方法

getRowLabel() 方法用于返回图表的行标签。

@Override
protected String getRowLabel(double totalArrivals) {log.debug("Total arr: " + totalArrivals);return "Arrival Rate (~" + Math.round(totalArrivals) + " total arrivals)";
}
  • 功能:返回图表的行标签,显示总到达数。
  • 关键点:通过 Math.round(totalArrivals) 计算总到达数,并生成标签。
2.2.2.1.9 createLoadPanel() 方法

createLoadPanel() 方法用于创建负载配置面板。

@Override
protected ParamsPanel createLoadPanel() {LoadParamsFieldsPanel loadFields = new LoadParamsFieldsPanel("Target Rate (arrivals/sec): ", "Ramp Up Time (sec): ", "Hold Target Rate Time (sec): ");loadFields.addUpdateListener(this);return loadFields;
}
  • 功能:创建负载配置面板,允许用户配置目标 RPS、Ramp-Up 时间和 Hold 时间。
  • 关键点:通过 LoadParamsFieldsPanel 提供负载配置选项,并通过 addUpdateListener 添加更新监听器。

3. Arrivals Thread Group 的实际应用

3.1 安装插件

首先,通过 JMeter 插件管理器安装 Arrivals Thread Group 插件:

  1. 打开 JMeter,进入 Options -> Plugins Manager
  2. Available Plugins 中搜索 Arrivals Thread Group,然后点击安装。

3.2 配置 Arrivals Thread Group

  1. 在测试计划中添加 Arrivals Thread Group
  2. 配置参数:
    • Target Rate:目标 RPS。
    • Ramp-Up Time:达到目标 RPS 所需的时间。
    • Hold Time:保持目标 RPS 的时间。

3.3 运行测试

启动测试后,Arrivals Thread Group 会根据配置动态调整线程数,确保请求速率符合预期。


4. Arrivals Thread Group 的优势与局限性

4.1 优势

  • 更真实的负载模拟:动态调整线程数,避免传统线程组的负载波动。
  • 易于配置:通过简单的参数设置即可实现复杂的负载模式。
  • 广泛适用性:适用于需要精确控制 RPS 的场景,如 API 测试、微服务测试等。

4.2 局限性

  • 资源消耗较高:动态调整线程数可能会增加系统资源消耗。
  • 不适合固定负载场景:对于需要固定并发用户数的场景,传统线程组可能更合适。

6. 总结

Arrivals Thread Group 是 JMeter 中一个非常实用的插件,通过动态调整线程数来实现目标 RPS,能够更真实地模拟用户行为。通过源码分析,我们深入了解了其实现原理和核心功能。在实际性能测试中,合理使用 Arrivals Thread Group 可以帮助我们更精确地控制负载,提升测试效果。

希望本文能帮助你更好地理解和应用 Arrivals Thread Group!如果你有任何问题或建议,欢迎在评论区留言讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/9385.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

51单片机开发:定时器中断

目标&#xff1a;利用定时器中断&#xff0c;每隔1s开启/熄灭LED1灯。 外部中断结构图如下图所示&#xff0c;要使用定时器中断T0&#xff0c;须开启TE0、ET0。&#xff1a; 系统中断号如下图所示&#xff1a;定时器0的中断号为1。 定时器0的工作方式1原理图如下图所示&#x…

Greenplum临时表未清除导致库龄过高处理

1.问题 Greenplum集群segment后台日志报错 2.回收库龄 master上执行 vacuumdb -F -d cxy vacuumdb -F -d template1 vacuumdb -F -d rptdb 3.回收完成后检查 仍然发现segment还是有库龄报警警告信息发出 4.检查 4.1 在master上检查库年龄 SELECT datname, datfrozen…

小程序-视图与逻辑

前言 1. 声明式导航 open-type"switchTab"如果没有写这个&#xff0c;因为是tabBar所以写这个&#xff0c;就无法跳转。路径开始也必须为斜线 open-type"navigate"这个可以不写 现在开始实现后退的效果 现在我们就在list页面里面实现后退 2.编程式导航…

Kotlin开发(六):Kotlin 数据类,密封类与枚举类

引言 想象一下&#xff0c;你是个 Kotlin 开发者&#xff0c;敲着代码忽然发现业务代码中需要一堆冗长的 POJO 类来传递数据。烦得很&#xff1f;别急&#xff0c;Kotlin 贴心的 数据类 能帮你自动生成 equals、hashCode&#xff0c;直接省时省力&#xff01;再想想需要多种状…

games101-作业2

图形管线 Vertex Processing 对顶点进行加工&#xff0c;使其变换到屏幕空间坐标。 Triangle Processing 将加工后的顶点组装成三角形&#xff0c;用于下一步的光栅化。 void rst::rasterizer::draw(pos_buf_id pos_buffer, ind_buf_id ind_buffer, col_buf_id col_buffer, Pr…

Baklib引领企业内容中台建设的新思路与应用案例

内容概要 在数字化转型的浪潮中&#xff0c;内容中台的概念逐渐成为企业实现高效运营的重要基础。内容中台不仅是信息资产的集中管理平台&#xff0c;更是企业在应对快速变化市场需求时的一种敏捷响应机制。通过搭建内容中台&#xff0c;企业能够有效整合各类资源&#xff0c;…

准备知识——旋转机械的频率和振动基础

旋转频率&#xff0c;也称为转速或旋转速率&#xff08;符号ν&#xff0c;小写希腊字母nu&#xff0c;也作n&#xff09;&#xff0c;是物体绕轴旋转的频率。其国际单位制单位是秒的倒数(s −1 )&#xff1b;其他常见测量单位包括赫兹(Hz)、每秒周期数(cps) 和每分钟转数(rpm)…

Java 大视界 -- Java 大数据在生物信息学中的应用与挑战(67)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

【NLP251】NLP RNN 系列网络

NLP251 系列主要记录从NLP基础网络结构到知识图谱的学习 &#xff11;.原理及网络结构 &#xff11;.&#xff11;&#xff32;&#xff2e;&#xff2e; 在Yoshua Bengio论文中( http://proceedings.mlr.press/v28/pascanu13.pdf )证明了梯度求导的一部分环节是一个指数模型…

Unbutu虚拟机+eclipse+CDT编译调试环境搭建

问题1: 安装CDT&#xff0c;直接Help->eclipse Market space-> 搜cdt , install&#xff0c;等待重启即可. 问题2&#xff1a;C变量不识别vector ’could not be resolved 这是库的头文件没加好&#xff0c;右键Properties->C Build->Enviroment&#xff0c;增加…

关于opencv环境搭建问题:由于找不到opencv_worldXXX.dll,无法执行代码,重新安装程序可能会解决此问题

方法一&#xff1a;利用复制黏贴方法 打开opencv文件夹目录找到\opencv\build\x64\vc15\bin 复制该目录下所有文件&#xff0c;找到C:\Windows\System32文件夹&#xff08;注意一定是C盘&#xff09;黏贴至该文件夹重新打开VS。 方法二&#xff1a;直接配置环境 打开opencv文…

OpenEuler学习笔记(十五):在OpenEuler上搭建Java运行环境

一、在OpenEuler上搭建Java运行环境 在OpenEuler上搭建Java运行环境可以通过以下几种常见方式&#xff0c;下面分别介绍基于包管理器安装OpenJDK和手动安装Oracle JDK的步骤。 使用包管理器安装OpenJDK OpenJDK是Java开发工具包的开源实现&#xff0c;在OpenEuler上可以方便…

Flutter_学习记录_基本组件的使用记录

1.TextWidge的常用属性 1.1TextAlign: 文本对齐属性 常用的样式有&#xff1a; TextAlign.center 居中TextAlign.left 左对齐TextAlign.right 有对齐 使用案例&#xff1a; body: Center(child: Text(开启 TextWidget 的旅程吧&#xff0c;珠珠, 开启 TextWidget 的旅程吧&a…

Java面试题2025-并发编程进阶(线程池和并发容器类)

线程池 一、什么是线程池 为什么要使用线程池 在开发中&#xff0c;为了提升效率的操作&#xff0c;我们需要将一些业务采用多线程的方式去执行。 比如有一个比较大的任务&#xff0c;可以将任务分成几块&#xff0c;分别交给几个线程去执行&#xff0c;最终做一个汇总就可…

算法基础学习——二分查找(附带Java模板)

有单调性的数列一定可以使用二分&#xff0c;没有单调性的题目也可能可以使用二分&#xff1b; &#xff08;一&#xff09;整数二分 二分的本质&#xff1a; 在某个整数区间内&#xff0c;存在某种性质使得区间内左半边的数都不满足该性质&#xff1b;而右半边的数都满足该性…

【Redis】List 类型的介绍和常用命令

1. 介绍 Redis 中的 list 相当于顺序表&#xff0c;并且内部更接近于“双端队列”&#xff0c;所以也支持头插和尾插的操作&#xff0c;可以当做队列或者栈来使用&#xff0c;同时也存在下标的概念&#xff0c;不过和 Java 中的下标不同&#xff0c;Redis 支持负数下标&#x…

如何看待 OpenAI 的12天“shipmas”发布计划?

openAI的“Shipmas”并非单纯的营销活动,而是在用户增长、技术创新和市场竞争中的综合布局和战略体现。 史上最寒酸的发布会?继十月马斯克在好莱坞电影城高调发布特斯拉三款最新产品(无人出租车、无人巴士、人形机器人)后,十二月,OpenAI CEO 奥特曼宣布 OpenAI 将连续12…

1.26学习

misc buuctf-神秘龙卷风 下载附件后打开&#xff0c;果然是一个加密的压缩包&#xff0c;用工具对这个压缩包进行破解&#xff0c;根据题目的四位数字我们可以知道密码是四位数字&#xff0c;所以破解得到密码解压后看到的是一串密文&#xff0c;是Brainfuck密文&#xff0c;…

把本地搭建的hexo博客部署到自己的服务器上

配置远程服务器的git 安装git 安装依赖工具包 yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel安装编译工具 yum install -y gcc perl-ExtUtils-MakeMaker package下载git&#xff0c;也可以去官网下载了传到服务器上 wget https://www.ke…

Ollama 运行从 ModelScope 下载的 GGUF 格式的模型

本文系统环境 Windows 10 Ollama 0.5.7 Ollama 是什么&#xff1f; Ollama 可以让你快速集成和部署本地 AI 模型。它支持各种不同的 AI 模型&#xff0c;并允许用户通过简单的 API 进行调用 Ollama 的安装 Ollama 官网 有其下载及安装方法&#xff0c;非常简便 但如果希…