Load Performance Test
(k6)

Abdullah Fathi

What is Load Testing?

Load testing is a type of non-functional testing that checks the application’s performance under specific loads and conditions. It involves simulating multiple users accessing an application simultaneously or sending requests to the server concurrently

Why Load Test Important?

  1. Determining Capacity Limits: Load testing helps determine the system’s capacity limits by pushing the application to its maximum load-bearing capacity. This information is crucial for capacity planning, ensuring that the application can handle expected user loads without compromising performance or stability
  2. Identifying Performance Bottlenecks: Load testing helps identify performance bottlenecks, such as slow response times, high resource utilization, or scalability issues. By pinpointing these bottlenecks, appropriate optimizations and improvements can be implemented to enhance the overall performance of the system
  3. Reliability and Stability: Load testing validates the reliability and stability of the application by subjecting it to realistic loads. By uncovering any issues related to stability, such as crashes or resource exhaustion, load testing enables necessary optimizations to ensure a stable and robust system

What is Grafana k6?

Grafana k6 is an open-source load testing tool that makes performance testing easy and productive for engineering teams

Why k6?

When it comes to ensuring optimal performance and reliability of your web application, incorporating performance testing with k6 can be a game-changer. k6 is a performance testing tool designed for the modern web.

k6 Key Features

  • CLI tool with developer-friendly APIs.
  • Scripting in JavaScript ES2015/ES6 - with support for local and remote modules
  • Checks and Thresholds - for goal-oriented, automation-friendly load testing
  • Testing Capabilities: k6 is optimized for running high-load tests such as:
    • Load Tests: Putting load on the system to see how it behaves
    • Spike Tests: Load testing with sudden increase or decrease of the load
    • Stress Tests: Load testing to find the maximum amount of load the system can handle
    • Soak Tests: Load testing a system continuously and monitoring for memory leaks and behavior of the system

Run K6

Docker

docker run --rm -i grafana/k6 run - <script.js

docker run --rm -i grafana/k6 run --out influxdb="https://influxdb.fotia.com.my/myk6db" - <k6-test.js

CLI

k6 run script.js

k6 run --out influxdb="https://influxdb.fotia.com.my/myk6db" k6-test.js

k6 Extension (xk6)

# Install xk6
go install go.k6.io/xk6/cmd/xk6@latest
# Build a k6 extension
xk6 build --with github.com/grafana/xk6-dashboard@latest
# LINUX
docker run --rm -u "$(id -u):$(id -g)" -v "${PWD}:/xk6" grafana/xk6 build \
  --with github.com/grafana/xk6-dashboard \
  --with github.com/grafana/xk6-sql \
  --with github.com/grafana/xk6-output-influxdb

# WINDOWS
docker run --rm -e GOOS=windows -u "$(id -u):$(id -g)" -v "${PWD}:/xk6" `
  grafana/xk6 build --output k6.exe `
  --with github.com/grafana/xk6-dashboard `
  --with github.com/grafana/xk6-sql `
  --with github.com/grafana/xk6-output-influxdb
  
# Verify
./k6 version

# Run
./k6 run --out 'web-dashboard=open=true' k6-test.js
  • k6 runs multiple iterations in parallel with virtual users (VUs). In general terms, more virtual users means more simulated traffic.

  • VUs are essentially parallel while(true) loops. Scripts are written in JavaScript, as ES6 modules, so you can break larger tests into smaller pieces or make reusable pieces as you like.

Virtual Users (VUs)

Custom Test Script

Base Script

// init
export default function () {
  // vu code: do things here...
}

Set Options

import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
  vus: 10,
  duration: '30s',
};
export default function () {
  http.get('http://test.k6.io');
  sleep(1);
}

Custom Test Script

Ramp VUs up and down in stages

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 20 },
    { duration: '1m30s', target: 10 },
    { duration: '20s', target: 0 },
  ],
};

export default function () {
  const res = http.get('https://httpbin.test.k6.io/');
  check(res, { 'status was 200': (r) => r.status == 200 });
  sleep(1);
}

Execution Modes

  • Local: The test execution happens entirely on a single machine, container, or CI server
  • Distributed: the test execution is distributed across a Kubernetes cluster
  • Cloud: the test runs on k6 Cloud or Grafana Cloud k6

Results Output

Results Output

As k6 generates load for your test, it also makes metrics that measure the performance of the system

Metrics measure how a system performs under test conditions

 

Key metrics includes:

  • http_req_duration: the end-to-end time of all requests (that is, the total latency)
  • http_req_failed: the total number of failed requests
  • iterations: the total number of iterations

Metrics

There is 4 broad types of Metric:

  1. Counters: Sum values
  2. Gauges: Track the smallest, largest, and latest values
  3. Rates: Track how frequently a non-zero value occurs
  4. Trends: Calculates statistics for multiple values (like mean, mode or percentile)

Note

Threshold: To make a test fail a certain criteria

 Tags and groups: To filter metrics

Metrics

 All the metrics that start with http, iteration, and vu are built-in metrics, which get written to stdout at the end of a test

Define the HTTP requests to test the system with

Validate that the system is responding with the expected content

Validate that the system is responding with the expected content

Using k6

Configure test-run behavior

Validate that the system is responding with the expected content

 Import modules, or parts of modules, to use in the test scripts

Using k6

  • Speed up the test creation
  • Learn the k6 API quickly
  • Collaborate with non-coders to build tests

Load Test Types

Create a different risk profiles for the application by creating a different patterns of traffic

Test Type Cheatsheet

k6 can generate a lot of load from a single machine. With proper monitoring and script optimization, you might be able to run a rather large load test without needing distributed execution

  • A single k6 process efficiently uses all CPU cores on a load generator machine. Depending on the available resources, a single instance of k6 can run 30,000-40,000 simultaneous users (VUs). In some cases, this number of VUs can generate up to 300,000 HTTP requests per second (RPS).
  • Unless you need more than 100,000-300,000 requests per second (6-12M requests per minute), a single instance of k6 is likely sufficient for your needs.

Network

Hardware Consideration

Network throughput of the machine is an important consideration when running large tests. When running the test, use a tool like iftop in the terminal to view the amount of network traffic generated in real time

CPU

k6 is heavily multi-threaded, and will effectively utilize all available CPU cores. Large tests require a significant amount of CPU power. We recommend that you size the machine to have at least 20% idle cycles (up to 80% used by k6, 20% idle)

Memory

Memory consumption heavily depends on your test scenarios.
Simple tests use ~1-5MB per VU. (1000VUs = 1-5GB). Tests that use file uploads, or load large JS modules, can consume tens of megabytes per VU

k6 Dashboard

xk6-dashboard

Dashboard Output
(Static HTML)

  • Exa Advanced k6 Dashboard: 15080
  • k6 Load Testing Results: 2587
  • k6 Dashboard: 14801

Grafana Dashboard + InfluxDB

Useful utility libs for k6 scripts

Explore/Misc

Expand the potential use cases for k6.

k6 term definition

 Everything necessary to use the core k6 products in your daily operational work

Your feedback matters

There are no secrets to success. It is the result of preparation, hard work, and learning from failure. - Colin Powell

THANK YOU

Load Performance Test (k6)

By Abdullah Fathi

Load Performance Test (k6)

  • 166