Chapter 04Lesson 03~130 minutes

Thread Groups, Virtual Users, Ramp-Up, Loops, and Workload Modeling: Configuration, Design Patterns, and Trade-Offs

Mandatory design examples remain local: any executable profile discussed here must target only http://127.0.0.1:8000 under the Chapter 04 thread/rate/duration ceilings.

Workload configuration is a model-selection problem. Every choice—users or arrivals, loops or duration, ramp shape, one group or several classes, deterministic or randomized timing—changes what the experiment can validly claim.

Trade-offsRate-orientedDurationWorkload classesRepeatability

Learning objectives

  • Select fixed-user or arrival/rate-oriented behavior from the production demand mechanism.
  • Choose loops versus duration based on whether work count or time window is the experimental control.
  • Use ramp-up as a workload-shape decision, not a generic safety ritual.
  • Separate workload classes when their behavior and SLOs differ.
  • Choose deterministic/repeatable versus randomized schedules deliberately.
  • Use experimental features only with explicit pinning and a stable fallback.

1. Fixed users versus rate/open arrivals

Question Fixed/classic threads fit when... Rate/open thinking fits when...
What is bounded? A population of users/sessions. Incoming work/events over time.
Feedback from slowdown Users complete fewer iterations. New arrivals may continue and concurrency can grow.
Primary control Concurrent users + user behavior. Arrival/departure schedule.
Typical example Three call-center agents. Webhook/event arrivals.
Key evidence Active threads + iteration/sample throughput. Arrival schedule + achieved departures + active concurrency.

Neither model is inherently more realistic. “Realistic” means consistent with how demand is created in the system you are studying.

2. Iterations versus duration

Use a fixed Loop Count when the question is count-oriented: “execute each synthetic user workflow ten times.” Use duration/lifetime when the question is window-oriented: “hold this bounded workload for five minutes.” You can configure both, but then whichever stop condition is reached first governs the classic Thread Group.

For regression gates, duration can improve comparability when workload behavior is time-based, but only if warm-up and steady-state interpretation are defined. For functional workload-shape experiments, small loop counts make expected sample counts easier to verify.

3. Fast ramp versus gradual ramp

Ramp shape Useful when Risk if accidental
Immediate/very fast You intentionally test a startup burst/spike. Generator and target receive synchronized work unrelated to normal traffic.
Gradual Population genuinely comes online over time or you need a controlled transition. Too slow can consume most of a short test before full concurrency exists.
Staged/rate ramp Demand is expected to rise through levels. Changing rates too quickly can blur which level caused saturation.

Do not use ramp-up to hide a weak generator. If the injector cannot start or sustain the intended users, measure and resize the generator rather than stretching the schedule until the symptom disappears.

4. One Thread Group versus several workload classes

One group is easier to reason about when users share the same lifecycle and scenario. Separate groups are appropriate when workload classes have different populations, schedules, timers, or scenario logic—for example, interactive readers versus periodic writers.

The cost is that concurrency and result interpretation become multidimensional. Use stable class-specific labels and manifests. Multiple groups that start at the same instant can also create a startup spike, so their start patterns must be designed rather than accidentally synchronized.

5. Deterministic versus randomized timing

Deterministic schedules improve run-to-run alignment and make debugging easier. Randomized arrivals can better model independent events and expose concurrency combinations that even spacing misses. Randomness does not mean “uncontrolled”: preserve the random seed when reproducibility matters.

The current Precise Throughput Timer supports a random seed. A non-zero seed can reproduce the same schedule; zero means a truly random/non-repeatable seed. Different rate-oriented groups should use different non-zero seeds if you want repeatability without accidentally synchronizing identical random schedules.

6. Stable built-ins versus experimental Open Model

The current Open Model Thread Group is built into JMeter but explicitly experimental. It offers expressive schedules such as:

rate(0) random_arrivals(30 sec) rate(2/sec)
random_arrivals(60 sec) rate(2/sec)
random_arrivals(30 sec) rate(0)
pause(10 sec)

That describes a scenario-arrival ramp, hold, ramp-down, and tail pause under current 5.6.3 semantics. Because the component may change, production governance should pin the exact JMeter release, preserve the schedule text, re-check current docs during upgrades, and keep a stable fallback.

A stable fallback for a simple sample-rate objective is classic Thread Group + Precise Throughput Timer. That fallback has different semantics: a pool of threads is throttled to a schedule; it is not a perfect replacement for an independent open-arrival process.

7. Precise Throughput Timer: useful rate target with explicit limits

The timer creates a randomized schedule of sampler departures. It cannot generate new threads, and the documentation warns that actual throughput can be lower if the server is too slow, other timers delay too much, there are not enough threads, or expensive test elements consume generator time.

It also does not promise an identical number of samples every one-second interval. Interpret it over the configured period and verify actual JTL throughput.

8. Worked scenario: two business workload classes

A local service has interactive users who keep at most three sessions active, plus an independent background job that should attempt roughly one operation per second.

  1. Interactive group: classic Thread Group, 3 users, gradual ramp, realistic think time, stable interactive labels.
  2. Background rate group: separate bounded classic pool with Precise Throughput Timer targeting the background rate; separate labels and manifest.
  3. Measure each class separately and in the combined test. Do not infer class-level performance from an unlabeled aggregate.
  4. If Open Model is selected for the background class, mark the test as release-pinned/experimental and preserve a fallback path.

9. Workload choices are not JVM/OS/SUT choices

Layer Examples Do not fix a workload-model problem by...
JMeter workload threads, ramp, loops, duration, timers Increasing JVM heap.
JVM/generator heap, GC, CPU Changing thread count merely to hide CPU saturation.
OS/network sockets, DNS, bandwidth Calling a network limit a server capacity result.
SUT queues, pools, DB, downstreams Changing JMeter timer until target telemetry looks good.
CI/container CPU quota, image, workspace Assuming the same JMX means the same injector capacity.

10. Decision table

Decision Prefer A Prefer B Required evidence
Fixed users vs rate Bounded population matters. Incoming work rate matters. Configured model + achieved throughput/concurrency.
Loops vs duration Exact scenario repetitions matter. Sustained time window matters. Actual count + observed wall window.
Fast vs gradual ramp Spike is intentional. Normal population buildup is intended. Thread-start/active-thread evidence.
One vs several groups One lifecycle/class. Distinct classes/SLOs/schedules. Per-class labels + manifests.
Deterministic vs random Debug/regression alignment. Independent arrival realism. Seed/schedule + run ID.
Stable vs experimental Governed baseline needed. Team accepts release-pinned experimental semantics. Version + explicit fallback + upgrade check.

11. Generator cost and measurement validity

More threads consume JVM objects, sockets, connection state, and scheduling resources. Rate timers can retain schedules. Multiple groups can synchronize accidentally. Long tests consume more result disk and environment time. The correct schedule is the smallest workload model that answers the performance question while the injector retains headroom.

Always compare configured demand with achieved samples/second, JTL thread counts, generator utilization, target active/queue state, and errors before making capacity or regression claims. Keep the matching jmeter.log so engine/runtime warnings are not mistaken for target behavior.

Knowledge check

When should separate Thread Groups represent workload classes?

Why can a very long ramp-up invalidate a short steady-load test?

What does a non-zero Precise Throughput Timer seed provide?

Why is classic Thread Group + Precise Throughput Timer only a fallback for open-arrival needs?

What must accompany use of the experimental Open Model Thread Group in a governed baseline?

Next lesson

Diagnose the load model before blaming the server

Lesson 4 turns common scheduling mistakes into incidents: thread-count-as-RPS assumptions, startup spikes, infinite-loop risk, duration-bound misconceptions, unlabeled classes, and experimental-feature drift.

Official references and version notes

  • Component Reference — current classic Thread Group, Open Model Thread Group, Precise Throughput Timer, and timer semantics.
  • Elements of a Test Plan — sampler ordering, Thread Groups, timer purpose/scope, and listener guidance.
  • Properties Reference — CSV result-save settings including thread-count fields and timestamp behavior.
  • Getting Started — GUI authoring versus CLI load execution and command-line behavior.
  • Best Practices — generator/listener practices for load execution.
  • Apache JMeter downloads — current production release and release-specific Java requirement.
Version and compatibility note

Version-sensitive statements were rechecked against current Apache JMeter primary documentation on 2026-09-04. The production baseline remains Apache JMeter 5.6.3; the release requires Java 8+, while mandatory labs use a Java 17 JDK. The classic Thread Group controls user/thread count, ramp-up, loops, and optional lifetime; with its scheduler, JMeter stops when loops finish or duration/end-time is reached, whichever occurs first, but the check happens between samples and an in-flight sampler waiting for a response is not forcibly ended by that scheduler boundary. The current Open Model Thread Group is explicitly marked experimental and may change; its schedule is evaluated at test start and its schedule end terminates/intercepts active scenario threads unless a tail pause(...) leaves time to finish. The stable mandatory rate-oriented path in this chapter uses the classic Thread Group plus the built-in Precise Throughput Timer. That timer does not create threads and cannot guarantee achieved throughput when too few threads, generator limits, target limits, or other delays prevent the schedule from being served.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.