【问题标题】:JMeter custom sampler synchronizationJMeter 自定义采样器同步
【发布时间】:2017-05-29 18:27:23
【问题描述】:

我正在制定一个 JMeter 测试计划,旨在对 Web 服务进行性能测试。整个测试计划的主要部分包括两个步骤。

  1. 从服务器检索 ID 列表(通过 Get-request)
  2. 获取其中一个 ID 并对其进行处理(通过 Post-request)

如果我使用单线程计划,一切都会按预期进行,但是一旦我使用多个线程,我就会进入竞争状态。问题是,第 2 步更改了可用 ID 列表,因此:如果线程 B 在线程 A 完成第 2 步之前检索 ID 列表,则线程 B 可能会获得与线程 A 相同的 ID,这会在线程 B 时导致错误试图完成第 2 步。不知何故,这是多线程环境中竞争条件的经典示例。 由于 JMeter 不提供定义关键代码块的可能性,我决定编写自己的自定义 Java 采样器,扩展 JMeter-AbstractJavaSamplerClient,覆盖 runTest() a.s.o。在 runTest() 实现中,我获取了 ReentrantLock 并使用它来锁定关键代码块。关键是,JMeter 似乎并不关心那个锁,我根本不明白为什么......如果我使用 Eclipse 通过远程调试来调试我的代码,我看到几个线程同时进入锁定的代码, 不应该是这样的。我还尝试了使用 synchronize 完成 runTest() 实现的老式方法,但这也不起作用。

有没有人有什么需要改变的建议?或者至少解释一下为什么这不起作用?

提前致谢!

【问题讨论】:

    标签: java multithreading synchronization jmeter


    【解决方案1】:

    另一种解决方法是编译一个简单的 java 类,将其编译并放入{JMETER_HOME}\apache-jmeter-3.1\lib\ext\ 文件夹中。

    import java.util.*;
    
    public class Global {
        public static Map map = new Hashtable();
    }
    

    使用 CMD 将其导出为 jar 文件

    jar cvfe {EXPORT_JAR_NAME}.jar ClassName {CLASS_FILE_NAME}.class
    

    将文件放入{JMETER_HOME}\apache-jmeter-3.1\lib\ext\文件夹。

    创建测试操作并将 JSR223 预处理器添加到测试计划中 Show Image

    import java.util.concurrent.Semaphore;
    
    Global.map.clear();
    
    Global.map.put("sem", new Semaphore(1));;
    

    创建另一个测试操作并将 JSR223 预处理器添加到测试计划中Show Image

    log.info(ctx.getThreadNum() + " ACQUIRE");
    Global.map.get("sem").acquire();
    for (def i = 0; i < 100; i++) {
      // Do something
      log.info(ctx.getThreadNum() + " DO SOMETHING " + i);
    }
    Global.map.get("sem").release();
    log.info(ctx.getThreadNum() + " RELEASE");
    

    它应该克服竞争条件,因为信号量在线程组之间是同步的。

    【讨论】:

      【解决方案2】:

      有 2 个选项可以让您在无需编写自己的采样器的情况下解决此问题。

      1. 最简单直接的解决方法是使用__threadNum 函数作为 ID 的参数,这样每个线程都可以操作自己的 ID
      2. 使用 Beanshell 脚本从作用域中删除当前正在使用的变量,以确保没有其他线程会选择相同的变量。

      任何 Beanshell 测试元素(采样器、后处理器、预处理器、断言等)都可以访问称为 vars 的东西,它是 JMeterVariables 类实例的简写。所以你应该可以使用:

      vars.put("key", "value"); // to add a variable
      vars.remove("key"); // to remove variable
      

      测试中任何地方的方法。

      请参阅How to use BeanShell: JMeter's favorite built-in component 指南了解更多详细信息和 Beanshell 食谱类型。

      【讨论】:

      • 嘿德米特里,感谢您的回答!我已经尝试过这些方法。第一个缺点是当线程数量增加时它变得不方便(我希望我能够使用多达 100 个线程进行负载测试......)。在这种情况下,定义哪个线程获取哪个 ID 的规则变得越来越困难。 Beanshell 脚本方法与我的原始方法有相同的缺点,因为它可能会进入竞争条件,例如,当 1 个线程检索列表并将其写入变量时,另一个线程已经在删除值。
      【解决方案3】:

      我终于让它运行了……我没有声明我的锁是静态的……因此有可能有几个线程进入了关键代码块。

      【讨论】:

        猜你喜欢
        • 2018-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多