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?
- 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
- 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
- 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:
- Counters: Sum values
- Gauges: Track the smallest, largest, and latest values
- Rates: Track how frequently a non-zero value occurs
- 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