WebSocket latency metric

I’m trying to benchmark a WebSocket echo server based on latency. My goal is to send as many messages as possible for 1 minute using X concurrent connections. I have written the following script:

import { WebSocket } from "k6/experimental/websockets";
import { Trend } from "k6/metrics";

export const options = {
  vus: __ENV.TOTAL_CLIENT,
  duration: "1m",
};

const url = __ENV.WS_URL;
const data = open(__ENV.DATA_FILE);
const duration = 60000; // 60s

const latency = new Trend("latency", true);

export default function () {
  const ws = new WebSocket(url);
  let start;

  ws.onopen = () => {
    const send = setInterval(() => {
      start = Date.now();
      ws.send(data);
    }, 1);

    ws.onmessage = (_) => {
      latency.add(Date.now() - start);
    };

    const close = setTimeout(() => {
      clearInterval(send);
      ws.close();
    }, duration);

    ws.onclose = () => {
      clearTimeout(close);
    };
  };
}

I also got the latency metric in the result:

     data_received.........: 86 MB 1.4 MB/s
     data_sent.............: 86 MB 1.4 MB/s
     iteration_duration....: avg=1m0s     min=1m0s     med=1m0s     max=1m0s     p(90)=1m0s     p(95)=1m0s   
     iterations............: 2     0.033332/s
     latency...............: avg=285.92µs min=0s       med=0s       max=2ms      p(90)=1ms      p(95)=1ms    
     vus...................: 2     min=2         max=2
     vus_max...............: 2     min=2         max=2
     ws_connecting.........: avg=552.37µs min=532.21µs med=552.37µs max=572.52µs p(90)=568.49µs p(95)=570.5µs
     ws_msgs_received......: 83159 1385.940918/s
     ws_msgs_sent..........: 83163 1386.007582/s
     ws_session_duration...: avg=1m0s     min=1m0s     med=1m0s     max=1m0s     p(90)=1m0s     p(95)=1m0s   
     ws_sessions...........: 2     0.033332/s

but i doubt that this is the correct way to get the latency metric, am i wrong? is there any other way?

Hi @bagashiz, welcome to the community forum!

The thing about websockets is that there is no request response pairs directly in the protocol, the same way that there is for HTTP. In HTTP it is part of the protocol that when you send a request you will get a single response back. And the time between the send and receive time is the latency between the two.

But Websockets have no such thing - everything is just a message. You can send 10 messages and get 0 messages back and that will be okay and expected behavior. If your particular use case has a request ↔ response pairs, than you need to match them and then add the latency between them.

What you currently did was that you send a bunch of messages and you receiving a bunch of them. But it is really likely that just after you’ve send a message you will get some message back. Which also very likely will not be the “response” for the message you just send.

I guess you can have a map with start times and some kind of identifier, but the identifier will need to come back with the (response) message so you can match it.

I guess you can also just get the average of how long it takes to complete for 1k messages and say that the average is the test_time/1k :person_shrugging:

Hope this helps you!