domingo, 17 de junho de 2012

How to dynamically increase/decrease load using JMeter

Recently, in JMeter's Users Mailing List, a member asked if is possible to make a dynamic threading model using JMeter and the answer to this question instigated me.

So, is it possible to setup a dynamic threading model using JMeter?

For this post I'm using JMeter 2.7, but it would work on earlier versions too.

Part 1 - Setting up the magic

 - Create a file and, in its content, write the number of initial threads to be executed. Example: If I want to increase the load 10 by 10 and start the test only with 5, I'll put 5 in the file content;
- Publish this file in a way it can be accessed by an HTTP Request Sampler.

Obs.: you could use any sampler you want, since it can access the file and the response can be extracted to a variable.

Part 2 - Setting up the test

* the ordered list is similar to the JMeter's script tree model.

1. Adding variables to Test Plan

    - maxThreads: the maximum number of threads you will run on the test

    Set maxThreads to 11, just for this test.


2. Adding a Thread Group

    - Number of threads: ${maxThreads}
    - Rampup: 0 (see details bellow)
    - Forever: checked (on earlier versions set Loop count to -1)




    If you want to use a Ramp-up interval, this will affect the start time of the last thread. Because of that the expressions used in If Controller component's conditions shown in this post have to be changed.

3. Adding the first If Controller

    - condition: ${__threadNum()} === ${maxThreads}

    What is it for?
    We'll use only one thread as a load controller.



    On a distributed testing you can use a different condition to run at only one JMeter server instance. I'll consider adding ${__machineName()} is suffice.

    - condition: (${__threadNum() === ${maxThreads}) && ("${__machineName()}" === "jmeter-server-1")

3.1. Adding an HTTP Request Sampler

    This sampler will access the file created and published at Part 1.



3.1.1. Adding a Regular Expression Extractor

    This post-processor will set a thread variable with the content of the response.

    Regular Expression: (.*)
    Model: $1$
    Match to number: 1
    Reference name: threads



    Regular Expression Post-Processor creates a thread variable that, by default, is not shared with others.
    We'll, then, add another component to share its value.

3.1.2. Adding a BSF Post-Processor

    This one will set a property used along by other threads.

    Language: javascript
    Script: var threads = vars.get("threads");
               props.put("currentThreads", threads);



3.2. (optional) Adding a Debug Sampler

    JMeter properties: True
    JMeter variables: True
    System properties: False



4. Adding the second If Controller

    - condition: ${__threadNum()} < ${maxThreads}

    This controller is needed only if you want to separate a thread specifically to item 3 of this post. If you prefer to reuse the thread to also execute the samplers, ignore this  controller and use item 4.1 as a substitute.



4.1. Adding the third If Controller

    - condition: ${__threadNum()} <= ${__P("currentThreads",0)}

    This controller condition will execute only the threads accordingly to the value defined in the file content published at "Part 1".



4.1.1. Here goes the test it self

    Bellow the third If Controller tree node will be added the samplers used by the real test scenario.

    Just for the proof of concept, add an HTTP Request Sampler and change its label to "__threadNum() = ${__threadNum()} & currentThreads = ${__P(currentThreads,0)}"



5. Adding a Results Tree Listener

    With this component we'll see what happens when the file, created and published at "Part 1", has its content updated.

6. Time to test

    My test setup:

        - threads.txt content: 0
        - maxThreads: 11
        - currentThreads 0
        - inside each sampler I added a Constant Timer with 1 second delay.

    Start the test. Look at Results Tree Listener. As we can see, only the sampler inside the first If Controller is executed.



    If we change the content of threads.txt to, let's say, 4, this will affect the test when next iteration starts.



Conclusion

    Yes. It's possible to achieve a dynamically controlled threading model. Although this can, hardly, be useful to short time tests, it makes more sense to long running threads, either using infinite Loop count, Runtime Controller, While Controller or other components or techniques. This is one way to do it and I believe that has some more.

    As a JMeter fan, I would like to see this feature added to JMeter in an easier way. As a developer, I have to learn more from JMeter code and contribute to improve this awesome tool.

** the script file can be downloaded here.

Um comentário: