🔥 0
0
Lesson 3 of 10 25 min +200 XP

Thread Groups & Realistic Load

A common mistake in performance testing: configuring 1,000 users to hit your server simultaneously and wondering why everything crashes. Real users don't behave that way.

This lesson teaches you to create realistic load patterns that reveal true performance issues.

Thread Group Fundamentals

The Three Core Settings

JMeter Thread Group Configuration
SettingWhat It ControlsTypical Value
Number of ThreadsTotal virtual users10-10,000
Ramp-up PeriodTime to start all threads30-300 seconds
Loop CountIterations per thread1-100 or Forever

Understanding Ramp-up

With 100 threads and 60-second ramp-up:

Time 0s:   ~1-2 threads active
Time 15s:  ~25 threads active
Time 30s:  ~50 threads active
Time 45s:  ~75 threads active
Time 60s:  100 threads active
Calculation: New thread every ramp-up / threads seconds = 60/100 = 0.6 seconds per new thread.

Why Ramp-up Matters

Bad: 0s Ramp-up

All users hit at once. Server sees instant spike. May trigger rate limiting or false failures.

Good: Gradual Ramp-up

Users arrive gradually. Server warms up. Caches populate. Realistic traffic pattern.

Thread Group Configuration

Basic Thread Group XML

<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup"
             testname="Product Shoppers">
  <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
  <elementProp name="ThreadGroup.main_controller" elementType="LoopController">
    <boolProp name="LoopController.continue_forever">false</boolProp>
    <stringProp name="LoopController.loops">10</stringProp>
  </elementProp>
  <stringProp name="ThreadGroup.num_threads">100</stringProp>
  <stringProp name="ThreadGroup.ramp_time">60</stringProp>
  <boolProp name="ThreadGroup.scheduler">true</boolProp>
  <stringProp name="ThreadGroup.duration">300</stringProp>
  <stringProp name="ThreadGroup.delay">0</stringProp>
</ThreadGroup>

Scheduler for Timed Tests

Enable the scheduler to run tests for a specific duration:

☑ Scheduler
Duration (seconds): 300  (5 minutes)
Startup delay (seconds): 0

This runs the test for exactly 5 minutes, regardless of loop count.

Think Time: Simulating Real Users

Real users don't make requests continuously. They:

  • Read product descriptions (5-15 seconds)
  • Compare prices (10-30 seconds)
  • Fill out checkout forms (30-60 seconds)
  • Think about purchases (varies widely)

Constant Timer

Adds a fixed delay after each request:

<ConstantTimer guiclass="ConstantTimerGui" testclass="ConstantTimer"
               testname="Read Product Page">
  <stringProp name="ConstantTimer.delay">5000</stringProp>
</ConstantTimer>
Problem: All users pause for exactly 5 seconds. Unrealistic.

Gaussian Random Timer (Recommended)

Adds variable delay with normal distribution:

<GaussianRandomTimer guiclass="GaussianRandomTimerGui"
                     testclass="GaussianRandomTimer"
                     testname="Realistic Think Time">
  <stringProp name="ConstantTimer.delay">5000</stringProp>
  <stringProp name="RandomTimer.range">2000</stringProp>
</GaussianRandomTimer>

This creates think times between 3-7 seconds (5000ms +/- 2000ms), following a bell curve.

Uniform Random Timer

Random delay within a range (flat distribution):

<UniformRandomTimer guiclass="UniformRandomTimerGui"
                    testclass="UniformRandomTimer"
                    testname="Variable Delay">
  <stringProp name="ConstantTimer.delay">3000</stringProp>
  <stringProp name="RandomTimer.range">4000</stringProp>
</UniformRandomTimer>

Delay ranges from 3000ms to 7000ms, with equal probability for any value.

E-commerce Think Time Examples

ActionRealistic Think Time
Browse product listing2-5 seconds
View product details5-15 seconds
Add to cart1-2 seconds
View cart3-5 seconds
Fill checkout form30-60 seconds
Payment confirmation5-10 seconds
<!-- After viewing product details -->
<GaussianRandomTimer guiclass="GaussianRandomTimerGui"
                     testclass="GaussianRandomTimer"
                     testname="Read Product Details">
  <stringProp name="ConstantTimer.delay">10000</stringProp>
  <stringProp name="RandomTimer.range">5000</stringProp>
</GaussianRandomTimer>

<!-- After filling checkout form -->
<GaussianRandomTimer guiclass="GaussianRandomTimerGui"
                     testclass="GaussianRandomTimer"
                     testname="Fill Checkout Form">
  <stringProp name="ConstantTimer.delay">45000</stringProp>
  <stringProp name="RandomTimer.range">15000</stringProp>
</GaussianRandomTimer>

Load Patterns for E-commerce

Pattern 1: Steady State

Constant load to establish baseline performance:

Users: 500 (constant)
Duration: 30 minutes
Use case: Normal business hours
<ThreadGroup testname="Steady State">
  <stringProp name="ThreadGroup.num_threads">500</stringProp>
  <stringProp name="ThreadGroup.ramp_time">120</stringProp>
  <boolProp name="ThreadGroup.scheduler">true</boolProp>
  <stringProp name="ThreadGroup.duration">1800</stringProp>
</ThreadGroup>

Pattern 2: Step-up Load

Gradually increase to find breaking point:

Start: 100 users
Add: 100 users every 5 minutes
Max: 1000 users

Use the Stepping Thread Group plugin or multiple Thread Groups with delays:

<!-- Batch 1: Start immediately -->
<ThreadGroup testname="Users Batch 1">
  <stringProp name="ThreadGroup.num_threads">100</stringProp>
  <stringProp name="ThreadGroup.ramp_time">30</stringProp>
  <stringProp name="ThreadGroup.delay">0</stringProp>
</ThreadGroup>

<!-- Batch 2: Start after 5 minutes -->
<ThreadGroup testname="Users Batch 2">
  <stringProp name="ThreadGroup.num_threads">100</stringProp>
  <stringProp name="ThreadGroup.ramp_time">30</stringProp>
  <stringProp name="ThreadGroup.delay">300</stringProp>
</ThreadGroup>

<!-- Continue pattern... -->

Pattern 3: Spike Test (Flash Sale)

Sudden traffic surge:

Baseline: 200 users
Spike: 2000 users in 30 seconds
Duration of spike: 10 minutes
Return to baseline
<!-- Background traffic -->
<ThreadGroup testname="Regular Shoppers">
  <stringProp name="ThreadGroup.num_threads">200</stringProp>
  <stringProp name="ThreadGroup.ramp_time">60</stringProp>
  <stringProp name="ThreadGroup.duration">1800</stringProp>
</ThreadGroup>

<!-- Flash sale spike -->
<ThreadGroup testname="Flash Sale Rush">
  <stringProp name="ThreadGroup.num_threads">1800</stringProp>
  <stringProp name="ThreadGroup.ramp_time">30</stringProp>
  <stringProp name="ThreadGroup.delay">300</stringProp>
  <stringProp name="ThreadGroup.duration">600</stringProp>
</ThreadGroup>

Multiple Thread Groups

You can have multiple Thread Groups to simulate different user types:

Test Plan
├── Thread Group: Browsers (70% - just looking)
│   └── Browse products, no purchase
├── Thread Group: Buyers (25% - complete purchase)
│   └── Full checkout flow
└── Thread Group: Admins (5% - inventory updates)
    └── Backend operations
<ThreadGroup testname="Browsers">
  <stringProp name="ThreadGroup.num_threads">700</stringProp>
  <!-- Just browse products -->
</ThreadGroup>

<ThreadGroup testname="Buyers">
  <stringProp name="ThreadGroup.num_threads">250</stringProp>
  <!-- Complete checkout flow -->
</ThreadGroup>

<ThreadGroup testname="Admins">
  <stringProp name="ThreadGroup.num_threads">50</stringProp>
  <!-- Backend operations -->
</ThreadGroup>

Calculating Thread Count

Based on Expected Traffic

Peak users: 10,000 users/hour
Average session: 10 minutes
Concurrent users = (10,000 / 60) * 10 = ~1,667 concurrent

Add safety margin (50%): ~2,500 threads for testing

Based on Target Throughput

Target: 100 requests/second
Average think time: 5 seconds
Average requests per iteration: 10

Threads needed = (Target RPS * Think Time) / Requests per iteration
Threads = (100 * 5) / 10 = 50 threads

Add for variation: 75-100 threads

Common Mistakes

Mistake 1: Zero Think Time

Without think time, 100 threads can generate 10,000+ requests/second - far more than 100 real users would generate. Always add realistic delays.

Mistake 2: Too Fast Ramp-up

Ramping up 1,000 users in 10 seconds creates artificial spike. Use at least 1 second per 10 users as a minimum.

Mistake 3: Fixed Loop Count for Duration Tests

If you want a 30-minute test, use the scheduler with duration, not a fixed loop count. Loop count varies based on response times.

Key Takeaways

  • Ramp-up gradually: At least 1 second per 10 threads to avoid unrealistic spikes.
  • Always add think time: Real users pause between actions. Use Gaussian Random Timer for realism.
  • Match real patterns: Use scheduler for duration-based tests, multiple thread groups for user types.
  • Calculate threads from traffic: Base thread count on expected concurrent users, not total daily visitors.

Next Lesson

Your threads are configured realistically. But here's the catch: modern web apps use sessions, tokens, and dynamic data. Next, we'll master Correlation - the high-value skill that makes tests actually work with real applications.

🧠 Quick Quiz

Test your understanding of this lesson.

1

What happens if you set 100 threads with 0 second ramp-up?

2

What is 'think time' in performance testing?

3

Why use Gaussian Random Timer instead of Constant Timer?

JMeter Fundamentals