Level Easy: What are iterations, VUs, and how they relate?

I’m having some difficulties understanding exactly how virtual users, and iterations, interact…
I’ve already read the docs, specially these two links:

But, for me at least, it’s hard to understand exactly what’s an iteration, what’s a virtual user…

For example, imagine I was interested in this scenario:
My default function is just a http post request, and I want to simulate

  • 5 requests, per second, for 2 seconds
  • 15 requests, per second, for 10 seconds
  • 20 requests, per second, for 5 seconds
    I thought that the proper way was to use
export const options = {
  scenarios: {
    contacts: {
      executor: 'ramping-arrival-rate',
      timeUnit: '1s',
      preAllocatedVUs: 10,
      maxVUs: 200,
      stages: [
        { target: 5, duration: '2s' },
        { target: 15, duration: '10s' },
        { target: 20, duration: '5s' },
        { target: 0, duration: '10s' },
      ],
    },
  },
  thresholds: {
    http_req_duration: ['p(95)<60000'], //units in miliseconds 60000ms = 1m 
    http_req_failed: ['rate<0.01'], // http errors should be less than 1%
    checks: ["rate>0.99"]
  },
};

But then I got this result:

http_reqs......................: 4       0.070166/s
     iteration_duration.............: avg=41.13s   min=24.94s   med=42.3s    max=54.98s   p(90)=53.5s    p(95)=54.24s  
     iterations.....................: 4       0.070166/s
     vus............................: 126     min=10     max=126
     vus_max........................: 126     min=10     max=126

How come we only have 4 request, and not 260?

Hi @I_T

Welcome to the forum :tada:

Regarding the concepts themselves:

  • Virtual Users are an emulation of a user performing your script. You can consider them to be an execution agent which has loaded your script and its context and is responsible for running it. They load your script and run it, that’s it. In practice, if you ask k6 to run N VUs, it will make sure to spawn N concurrent components running your script repeatedly; effectively simulating N users performing the behavior you described in your script repeatedly.
  • Every time your script is executed (by a VU), that’s what we call an iteration. An iteration is always performed by a virtual user. Keep in mind that an iteration can produce different outcomes and take a different amount of time depending on what your script performs, though.

As a result, you can customize the behavior of k6 in pretty interesting ways, as you’ve already discovered, using scenarios. You can ask k6 to essentially have N virtual users running your script M times, and customize how those actions are distributed using different executors. For instance, the shared-iterations executors will make sure that a total of exactly M iterations are performed, and k6 will spawn up to N virtual users performing iterations until M is reached. Each executor basically implements a specific strategy that defines k6’s behavior when it comes to execute iterations using virtual users.

I hope that clarifies a bit more. Please let me know if you have further questions on that front :slight_smile:

Regarding your script, would you be comfortable sharing your test script (anonymized, of course)? I have tried running the simplest example I could think of using your configuration and didn’t reach the same output.

Here’s my test script and full output for reference:

import http from 'k6/http'

export const options = {
    scenarios: {
        contacts: {
            executor: 'ramping-arrival-rate',
            timeUnit: '1s',
            preAllocatedVUs: 10,
            maxVUs: 200,
            stages: [
                { target: 5, duration: '2s' },
                { target: 15, duration: '10s' },
                { target: 20, duration: '5s' },
                { target: 0, duration: '10s' },
            ],
        },
    },
    thresholds: {
        http_req_duration: ['p(95)<60000'], //units in miliseconds 60000ms = 1m
        http_req_failed: ['rate<0.01'], // http errors should be less than 1%
        checks: ['rate>0.99'],
    },
}

export default function () {
    http.get('https://httpbin.org')
}

Results in

running (26.4s), 000/010 VUs, 292 complete and 0 interrupted iterations
contacts ✗ [====================================>-] 000/010 VUs  26.4s/27s  02 iters/s

   ✓ checks.........................: NaN%   ✓ 0        ✗ 0   
     data_received..................: 2.9 MB 111 kB/s
     data_sent......................: 31 kB  1.2 kB/s
     http_req_blocked...............: avg=11.98ms  min=180ns    med=400ns    max=441.07ms p(90)=450ns    p(95)=558ns   
     http_req_connecting............: avg=3.82ms   min=0s       med=0s       max=116.03ms p(90)=0s       p(95)=0s      
   ✓ http_req_duration..............: avg=128.15ms min=109.55ms med=116.71ms max=528.09ms p(90)=132.79ms p(95)=218.37ms
       { expected_response:true }...: avg=128.15ms min=109.55ms med=116.71ms max=528.09ms p(90)=132.79ms p(95)=218.37ms
   ✓ http_req_failed................: 0.00%  ✓ 0        ✗ 292 
     http_req_receiving.............: avg=67.05µs  min=36.54µs  med=60.96µs  max=461.22µs p(90)=84.11µs  p(95)=91.64µs 
     http_req_sending...............: avg=48.1µs   min=26.31µs  med=43.4µs   max=146.69µs p(90)=61.09µs  p(95)=81.94µs 
     http_req_tls_handshaking.......: avg=8.03ms   min=0s       med=0s       max=291.22ms p(90)=0s       p(95)=0s      
     http_req_waiting...............: avg=128.03ms min=109.46ms med=116.62ms max=527.97ms p(90)=132.68ms p(95)=218.23ms
     http_reqs......................: 292    11.05812/s
     iteration_duration.............: avg=140.21ms min=109.61ms med=116.85ms max=562.37ms p(90)=146.97ms p(95)=362.92ms
     iterations.....................: 292    11.05812/s
     vus............................: 10     min=10     max=10
     vus_max........................: 10     min=10     max=10

Cheers :bowing_man: