Beginner’s Guide to Load Testing with k6 — Part 1

7 minute read

Update: This article is part of a series on load testing. I will try to regularly publish related topics in this series. I won’t repeat this table of contents on every single article, so please check this very first one to get new updates. Also I will try to link articles together, so that you can easily follow the next one in the series. Ever since, these has been published:

Part 1 — The Prelude

Part 2 — Performance Goals and k6 Metrics

Part 3 — How to Write & Run a Load Test Using k6

Let’s start with some questions:

  • Have you ever thought about ways to find out if your infrastructure setup could stand under high loads of users?
  • Have you ever been able to run a load test without dealing with so many configurations and steep learning curve of current testing tools?
  • Have you ever thought about ways to script your way through testing, either for load/performance or otherwise?
  • Have you ever thought that performance testing can be simplified and be included as part of your CI/CD process? You are not alone in that. I remember days when I was the lead developer of a team working on developing an API to serve our ever-increasing set of Apps with many micro-services like content- and user-management, billing, analytics and the like. At that time, we used to use the latest best practices in software engineering in source control and CI/CD processes. We have set up our CI/CD process using docker and hosted GitLab and used GitLab CI to deal with CI process. After a while of testing and code-push, we have decided to go with an alpha-stage API that can answer our needs with a new App we used to develop.

After a while of development, testing and improvement, we decided to test our API under load to see if it can hold up to the promises. Since we have seen that after 200,000 users subscribing and 60,000 of them using one of our other Apps, there is an slow-down on the request/response flow to the other API, which roughly had the same setup.

So, in order to not miss the opportunity of (load) testing before customers coming in, we decided to investigate ways to load test our API. After our investigations into Locust, Apache JMeter and the like, we decided to go with Apache JMeter, which was (and still is) the tool of the trade. We thought it would be a good candidate for this purpose. It took us almost three days to be able to learn and execute simple load tests with the GUI version. We were able to produce load test from one server and analyze the results. The results were good, because it gave us a bit more insight into what we should expect from our API, in terms of number of concurrent users and our API’s response time under load.

But later we didn’t use the tool, since there was no clear way to integrate it into our CI/CD process at that time, and we didn’t have enough time to learn and use it. We wanted something more developer-friendly, more integrable to our workflow, and easier to learn. Nowadays, it has been improved very much and it integrates with CI/CD pipelines easily.

Now, I am working for a company, Load Impact, which deals with load and performance testing as their core business. They have a FOSS, easily scriptable tool (JavaScript), called k6, which can be used for load testing. They also offer a cloud service on top of the same exact tool, for provisioning and running the tests, from different regions of the world Cloud Execution, and it finally give you a nice dashboard with analyzed results of the tests with shiny charts. It also has good integrations with CI/CD tools and platforms.

Load test script written in JavaScript:

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

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

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

Enough said! Let’s dive deep into what load testing is and how we can use k6 for doing load testing on our infrastructure. I will try to write more about the cloud service in the future, too.

What is Load/Performance Testing?

Performance testing is a subset of performance engineering in computer science practice which deals with quality assurance of software by putting pressure and workload, either manually or automatically, on the software to see how it behaves and to make sure it is responsive and stable enough under that load. It’s all about expectations. For example, you expect your API or website to serve 10K users simultaneously, but when you put pressure on it, it quickly becomes evident that your calculations differs from the reality and the reverse proves to be the case. Then you should analyze the weak points in your design or setup to see how you can benefit from high load.

There are many types of tests catered for different purposes in performance testing (Source: https://en.wikipedia.org/wiki/Software_performance_testing):

  • Load testing: basically, putting load on the system to see how it behaves.
  • Stress testing: load testing to find the maximum amount of load the system can handle.
  • Soak testing: load testing a system continuously and monitoring for memory leaks and behavior of the system.
  • Spike testing: load testing with sudden increase or decrease of the load.
  • Breakpoint testing: like stress testing, but incremental load is put on the system over time to see how it behaves.
  • Configuration testing: changing configuration to see how the system behaves under different configurations, under load.
  • Isolation testing: Isolating a fault domain and repeating the test to confirm the failure.
  • Internet testing: global load testing for big companies to see how to system behaves from different regions. The most common purpose of performance testing is to find out how reliable, stable, performant and responsive the system is. Metrics like throughput and response time is a good measure of such a system.

k6: Scripting and Running Load Tests and Interpreting The Results

k6 is a Free/Open-Source tool, written in Go, which can ingest tests written in JavaScript (ES5.1+) and turn them into requests to load test your website or API.

The easiest possible way to use k6 is to install it on your machine using a official prebuilt binary version. k6 supports Microsoft Windows with an MSI installer, GNU/Linux with an APT repository and Apple macOS using brew.

There is also an official docker image. It is not recommended for beginners to build from source, but you always have the option to do that.

You can then run your installed k6 command with the following script:

import { check } from "k6";
import http from "k6/http";

export default function() {
  let res = http.get("https://test.loadimpact.com/");
  check(res, {
    "is status 200": (r) => r.status === 200
  });
};

A sample test script for k6

Once you have saved this script somewhere accessible to k6, naming it script.js or your own desired file name, you can run it with 10 virtual users (VU) and over a period of 30 seconds, as follows:

k6 run -u 10 -d 30s script.js

It basically runs k6 on your machine using 10 virtual users over the course of 30 seconds, and it checks to see if the test URL returns 200 (OK) in all tests.

The output of running this command would be as below. I recommend you to have a look at it to better understand different metrics, checks and other key-values. This output will be thoroughly explained in the next articles.

By interpreting the current output, you can see that the script is locally executed for the duration of 30 seconds and spawned 10 separate virtual users (vus) to test the URL. You can also see the highlighted green checked item, “is status 200”, that signifies that our check has passed for 100% of the cases, meaning all cases.

The total data sent and received in 2775 requests is also present. For each HTTP requests, there is a http_req_ metric (key) with 5 different values, each corresponding to the average, minimum, median, maximum, 90th percentile and 95th percentile of all the requests.

Terminal output of the sample test script for k6
Terminal output of the sample test script for k6

This was a very short introduction to performance/load testing and the k6 tool. I will try to write more advanced load testing articles to show you how to load test your website and/or API.

This series will continue with more in-depth performance/load testing articles assuming the readers don’t have previous experience on this topic.

In the next article in this series, I will try to talk about performance goals and k6 metrics, which are the building blocks of load testing.

As always, I do really appreciate your suggestions, comments and inputs on this. And I would like to thank Pepe Cano and Robin Gustafsson for their valuable comments and suggestions on this article and the series.

Updated:

Comments