Scenarios And Executors In Grafana K6:A Quick Overview

Reading Time: 5 minutes

Hello there, buddies!

With the aid of Grafana k6, we will investigate scenarios and executors in the load testing tool with various sorts of APIs in this brief blog. But you might be wondering what the situations are and why we employ them. So, let’s start with the fundamental concepts of scenarios.

Scenarios are a grouping of transactions or scripts that we use to imitate real-world challenges and circumstances in your environment.

I hope you have a basic understanding of scenarios after reading the definition. We’ll learn more about situations and executors in this blog. But before that, Let’s know more about k6

What is Grafana k6

k6, formerly known as load impact, is an open-source load testing tool that can be used to assess the performance of APIs, microservices, and webpages. You can use k6 to evaluate your systems’ reliability and performance, catching performance regressions and problems earlier. To make performance testing more efficient, we may utilize scenarios, which replicate real-world obstacles and events that individuals confront in their everyday lives. So, Let’s take a closer look at the scenarios.

Scenarios

Scenarios allow us to customize how VUs and iterations are schedule in great detail. This allows load tests to replicate a variety of traffic patterns.

The following are some of the advantages of employing scenarios:

  • Multiple scenarios can be stated in a single script, each of which can execute a distinct JavaScript function independently, making test organization easier and more versatile.
  • A purpose-built executor can be used to create a unique VU and iteration scheduling scheme for each circumstance. This allows for the simulation of advanced execution patterns that are more accurate in simulating real-world traffic.
  • Scenarios are independent of one another and operate in parallel, though the startTime property of each can be carefully specified to make them appear sequential.
  • Each scenario can have its own set of environment variables and metric tags.

There is no library available in the k6 to import the scenarios, so, we must first extend the options object in k6 and then mention the scenarios name and pass the keys value pairs, also known as executors.

export const options = {
  scenarios: {
    my_scenario: {
      
      executor: 'shared-iterations',     // name of the executor to use
      startTime: '10s',             // common scenario configuration
      gracefulStop: '5s',
      env: { EXAMPLEVAR: 'testing' },
      tags: { example_tag: 'testing' },
      vus: 10,                    // executor-specific configuration
      iterations: 2,
      maxDuration: '10s',
    },
    another_scenario: {
      /*...*/
    },
  },
};

As you can see above, we use executors, which play a vital role in the scenarios. In order to gain a better grasp, we need to study and explore more about executors, so let’s take a closer look at executors now.

Executors

Executors are the k6 engine’s CPU; basically, they are also known as engine workhorses. Each one has a distinct schedule for VUs and iterations, and you’ll choose one based on the type of traffic you want to simulate to test your services.

There are different types of executors available in the market for different purposes.

So let’s explore them one by one.

1. Shared iterations

A certain number of iterations are “shared” among a number of VUs, and the test is completed after all iterations are completed. The global vus and iterations shortcut options are similar to this executor.

It’s important to keep in mind that this executor is appropriate when you need a specified number of VUs to finish a certain number of total iterations, but the number of iterations per VU isn’t important. This executor will make the most “efficient” use of VUs, thus if you need to complete a large number of test iterations quickly.

export const options = {
  scenarios: {
      executor: 'shared-iterations',   //(5/5)=1 iterations per vus
      vus: 5,
      iterations: 5,
      statTime: '3s',
    },
  },

2. Per-vu-iterations

Each VU performs a specific number of iterations. Vus * iterations will be the total number of completed iterations. If you need a specified number of VUs to finish the same number of iterations, use this executor. When you have fixed sets of test data that you want to segregate between VUs, this can be handy.

export const options = {
  scenarios: {
      executor: 'per-vu-iterations',    // 5*5=25 iterations
      vus: 5,
      iterations: 5,
      maxDuration: '3s',
    },
  },

3. Constant-vus

For a given amount of time, a fixed number of VUs perform as many iterations as possible. The global vus and duration options are equivalent to this executor. If you require a specified number of VUs to run for a specific amount of time, use this executor.

export const options = {
  scenarios: {
      executor: 'constant-vus',
      vus: 5,
      duration: '3s',
    },
  },

4. Ramping VUs

For a given period of time, a variable number of VUs perform as many iterations as possible. The global stages option is equal to this executor. If you require VUs to ramp up or down over a set length of time, this executor is a suitable choice.

export const options = {
  scenarios: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '10s', target: 5 },
        { duration: '5s', target: 0 },
      ],
    },
  }

5. Constant arrival rate

In a specific amount of time, a certain number of iterations are initiated. As long as there are VUs available, this executor will continue to initiate iterations at the specified rate. Because test logic or the system-under-test reacting slowly can cause iteration execution time to fluctuate.

This executor is a suitable choice when you wish to keep the number of iterations constant regardless of the performance of the system being tested.

export const options = {
  scenarios: {
      executor: 'constant-arrival-rate',

      // Our test should last 20 seconds in total
      duration: '20s',

      // It should start 20 iterations per `timeUnit`. Note that iterations starting points
      // will be evenly spread across the `timeUnit` period.
      rate: 5,
      timeUnit: '1s',    // It should start `rate` iterations per second
      preAllocatedVUs: 2,  // It should preallocate 2 VUs before starting the test
      maxVUs: 10,    // It is allowed to spin up to 10 maximum VUs in order        to sustain the defined
    },
  },
};

6. Ramping arrival rate

Over a given length of time, a variable number of iterations are started. This is similar to the ramping VUs executor, however, it only works with iterations. To accomplish the chosen iteration rate, k6 will attempt to dynamically adjust the number of VUs.

If you require your tests to be unaffected by the performance of the system-under-test and want to ramp up or down the number of iterations over particular time periods then this executor is a more suitable choice.

export let options = {
  scenarios: {
      executor: "ramping-arrival-rate",

      // Our test with at a rate of 2 iterations started per `timeUnit` (e.g minute).
      startRate: 2,
      timeUnit: "1s",  // It should start `startRate` iterations per seconds

      // It should preallocate 2 VUs before starting the test.
      preAllocatedVUs: 2,
      maxVUs: 20,   // It is allowed to spin up to 20 maximum VUs in order to sustain the defined

      stages: [
        // It should start 5 iterations per `timeUnit` for the first 2 seconds.
        { target: 5, duration: "2s" },
        { target: 10, duration: "10s" },
        { target: 15, duration: "15s" },
        { target: 2, duration: "2s" },
      ],
    },
  },

7. Externally controlled

k6’s REST API or CLI can be used to control and scale execution during runtime.

The pause, resume and scale CLI commands were previously used to manage k6 execution globally. This executor accomplishes the same goal by offering a more user-friendly API for controlling k6 execution at runtime.

If you wish to limit the amount of VUs used during the test it is the best choice. To run commands like pause, resume, and scale, we need to split the terminal like below.

export const options = {
  externally_controller_scenario: {
      executor: 'externally-controlled',
      vus: 10,
      maxVUs: 30,
      duration: '2m',
    },
  },

That’s all for this blog, I Hope so you enjoyed and learned about the scenarios and executors in k6, and in the next blog, we will learn more about it, so stay tuned.

Thank you!!  

References:

https://k6.io/

knoldus

Written by 

I am a Software Consultant in knoldus software limited, I have 6 months past experience and I am a quick learner, self-motivated, and etc

Leave a Reply