Load test API with K6
Many things can go wrong when a system is under load. The system must run numerous operations simultaneously and respond to different requests from a variable number of users. To prepare for these performance risks, teams use load testing.
But a good load-testing strategy requires more than just executing a single script. Different patterns of traffic create different risk profiles for the application. For comprehensive preparation, teams must test the system against different test types.
Installation
k6 has packages for Linux, Mac, and Windows. Alternatively, you can use a Docker container or a standalone binary.
Debian/Ubuntu
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
Fedora/CentOS
Using dnf (or yum on older versions):
sudo dnf install https://dl.k6.io/rpm/repo.rpm
sudo dnf install k6
MacOS
Using Homebrew:
brew install k6
Windows
If you use the Chocolatey package manager
you can install the unofficial k6 package with:
choco install k6
If you use the Windows Package Manager, install the official packages from the k6 manifests (created by the community)
winget install k6
Alternatively, you can download and run the latest official installer.
Docker
docker pull grafana/k6
Different tests for different goals
Start with smoke tests, then progress to higher loads and longer durations.
The main types are as follows. Each type has its own article outlining its essential concepts.
- Smoke tests validate that your script works and that the system performs adequately under minimal load.
- Average-load test assess how your system performs under expected normal conditions.
- Stress tests assess how a system performs at its limits when load exceeds the expected average.
- Soak tests assess the reliability and performance of your system over extended periods.
- Spike tests validate the behavior and survival of your system in cases of sudden, short, and massive increases in activity.
- Breakpoint tests gradually increase load to identify the capacity limits of the system.
Test-type cheat sheet
The following table provides some broad comparisons.
Smoke Test
Smoke tests have a minimal load. Run them to verify that the system works well under minimal load and to gather baseline performance values.
This test type consists of running tests with a few VUs — more than 5 VUs could be considered a mini-load test.
Similarly, the test should execute for a short period, either a low number of iterations or a duration from seconds to a few minutes maximum.
import http from 'k6/http';
import { check, sleep} from 'k6';
export const options = {
vus: 3, // Key for Smoke test. Keep it at 2, 3, max 5 VUs
duration: '1m', // This can be shorter or just a few iterations
};
export default () => {
const urlRes = http.req('https://test-api.k6.io');
sleep(1);
// MORE STEPS
// Here you can have more steps or complex script
// Step1
// Step2
// etc.
};
Load testing
An average-load test assesses how the system performs under typical load. Typical load might be a regular day in production or an average moment.
Average-load tests simulate the number of concurrent users and requests per second that reflect average behaviors in the production environment. This type of test typically increases the throughput or VUs gradually and keeps that average load for some time. Depending on the system’s characteristics, the test may stop suddenly or have a short ramp-down period.
import http from 'k6/http';
import {sleep} from 'k6';
export const options = {
// Key configurations for avg load test in this section
stages: [
{ duration: '5m', target: 100 }, // traffic ramp-up from 1 to 100 users over 5 minutes.
{ duration: '30m', target: 100 }, // stay at 100 users for 10 minutes
{ duration: '5m', target: 0 }, // ramp-down to 0 users
],
};
export default () => {
const urlRes = http.req('https://test-api.k6.io');
sleep(1);
// MORE STEPS
// Here you can have more steps or complex script
// Step1
// Step2
// etc.
};
Stress testing
Stress testing assesses how the system performs when loads are heavier than usual.
The load pattern of a stress test resembles that of an average-load test. The main difference is higher load. To account for higher load, the ramp-up period takes longer in proportion to the load increase. Similarly, after the test reaches the desired load, it might last for slightly longer than it would in the average-load test.
import http from 'k6/http';
import {sleep} from 'k6';
export const options = {
// Key configurations for Stress in this section
stages: [
{ duration: '10m', target: 200 }, // traffic ramp-up from 1 to a higher 200 users over 10 minutes.
{ duration: '30m', target: 200 }, // stay at higher 200 users for 10 minutes
{ duration: '5m', target: 0 }, // ramp-down to 0 users
],
};
export default () => {
const urlRes = http.req('https://test-api.k6.io');
sleep(1);
// MORE STEPS
// Here you can have more steps or complex script
// Step1
// Step2
// etc.
};
Soak testing
Soak testing is another variation of the Average-Load test. It focuses on extended periods, analyzing the following:
- The system’s degradation of performance and resource consumption over extended periods.
- The system’s availability and stability during extended periods.
The soak test differs from an average-load test in test duration. In a soak test, the peak load duration (usually an average amount) extends several hours and even days. Though the duration is considerably longer, the ramp-up and ramp-down periods of a soak test are the same as an average-load test.
import http from 'k6/http';
import {sleep} from 'k6';
export const options = {
// Key configurations for Soak test in this section
stages: [
{ duration: '5m', target: 100 }, // traffic ramp-up from 1 to 100 users over 5 minutes.
{ duration: '8h', target: 100 }, // stay at 100 users for 8 hours!!!
{ duration: '5m', target: 0 }, // ramp-down to 0 users
],
};
export default () => {
const urlRes = http.req('https://test-api.k6.io');
sleep(1);
// MORE STEPS
// Here you can have more steps or complex script
// Step1
// Step2
// etc.
};
Spike testing
A spike test verifies whether the system survives and performs under sudden and massive rushes of utilization.
Spike tests are useful when the system may experience events of sudden and massive traffic. Examples of such events include ticket sales (Taylor Swift), product launches (PS5), broadcast ads (Super Bowl), process deadlines (tax declaration), and seasonal sales (Black Friday). Also, spikes in traffic could be caused by more frequent events such as rush hours, a particular task, or a use case.
Spike testing increases to extremely high loads in a very short or non-existent ramp-up time. Usually, it has no plateau period or is very brief, as real users generally do not stick around doing extra steps in these situations. In the same way, the ramp-down is very fast or non-existent, letting the process iterate only once.
This test might include different processes than the previous test types, as spikes often aren’t part of an average day in production. It may also require adding, removing, or modifying processes on the script that were not in the average-load tests.
Occasionally, teams should revamp the system to allow or prioritize resources for the high-demand processes during the event.
import http from 'k6/http';
import {sleep} from 'k6';
export const options = {
// Key configurations for spike in this section
stages: [
{ duration: '2m', target: 2000 }, // fast ramp-up to a high point
// No plateau
{ duration: '1m', target: 0 }, // quick ramp-down to 0 users
],
};
export default () => {
const urlRes = http.req('https://test-api.k6.io');
sleep(1);
// MORE STEPS
// Add only the processes that will be on high demand
// Step1
// Step2
// etc.
};
Breakpoint testing
Breakpoint testing aims to find system limits. Reasons you might want to know the limits include:
- To tune or care for the system’s weak spots to relocate those higher limits at higher levels.
- To help plan remediation steps in those cases and prepare for when the system nears those limits.
In other words, knowing where and how a system starts to fail helps prepare for such limits.
A breakpoint ramps to unrealistically high numbers. This test commonly has to be stopped manually or automatically as thresholds start to fail. When these problems appear, the system has reached its limits.
import http from 'k6/http';
import {sleep} from 'k6';
export const options = {
// Key configurations for breakpoint in this section
executor: 'ramping-arrival-rate', //Assure load increase if the system slows
stages: [
{ duration: '2h', target: 20000 }, // just slowly ramp-up to a HUGE load
],
};
export default () => {
const urlRes = http.req('https://test-api.k6.io');
sleep(1);
// MORE STEPS
// Here you can have more steps or complex script
// Step1
// Step2
// etc.
};