Load testing WebSockets with k6

I needed to test a WebSocket server implementation, to make sure nothing caught fire under load.

To do that, I liked the look of k6—which does more than just WebSockets—and it worked well. It’s easy to code against with JavaScript (looks like Typescript support is on the way).

The config is straightforward, and there’s much more control if you need it:

export let options = {
stages: [
{ duration: "1m", target: 60 }, // Stage 1 lasts 1 minute and builds up to 60 users
{ duration: "2m", target: 600 }, // Ramp up to 600 users
{ duration: "10m", target: 600 }, // Soak test for 10 minutes
{ duration: "2m", target: 0 }, // Ramp down
],
// Targets to report against:
thresholds: {
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
},
};

The actual test is in one export function. I’ve pasted an example over at GitHub.

That example:

  • uses a session cookie for authentication (an interesting topic in its own right).
  • It opens up a couple of web socket endpoints, sits there for a bit, then disconnects.

The run is:

$ brew install k6
$ k6 run -e USER_PASSWORD=trustn01 example.js

…and then go make some coffee.

At the end of the run, after ramping up and cooling down, you get a nice report of timings and errors.


Two things I found useful:

  • To debug HTTP requests, add --http-debug
  • You likely want to use ws:// endpoints trying this out locally, then switch to wss:// to test against a more realistic environment.