0
0

More than 1 year has passed since last update.

k6でwebsocketを扱う

Last updated at Posted at 2022-10-03

k6って何?

オープンソースの負荷試験ツール。http 接続のみでなく、grpc や websocket にも対応している。
今回はこれを用いて WebSocket の負荷試験を行う。

インストール

公式サイト参照。ubuntuであれば以下のコマンドを打ち込む。
https://k6.io/docs/getting-started/installation/

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

この通り実行すればヨシ。

途中で

gpg: failed to create temporary file '/root/.gnupg/...(略)' : No such file or director

と言われたので確認したら、/root/.gnupg がなかったので作成した。

sudo mkdir /root/.gnupg

スクリプトの作成

以下の四つのステップによって成り立っている。

// 1. init

export function setup() {
// 2. step3を実行する前準備として一回だけ実行される
// ここの返り値をstep3の引数として渡すことができる
}

export default function (data) {
// 3. 試すテスト
}

export function teardown(data) {
// 4. 全テスト終了時に実行される
}
  1. init で他のモジュールからインポート等の前準備を行う
  2. setup でテスト前に必要な準備を行う。これはステップ3を行う前に一度だけ実行される
  3. default functionとして実行するテストを描く
  4. 全テスト終了時に実行される。

なおstep3以外は省略可能。default functionのみが実行される。

httpの場合の例

http接続の場合、例えば以下のようなスクリプトとなる。
https://k6.io/docs/using-k6/checks/

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

export const options = {
  vus: 10,
  iterations: 10,
};

export default function () {
  const res = http.get('http://test.k6.io/');
  check(res, {
    'verify homepage text': (r) =>
      r.body.includes('Collection of simple web-pages suitable for load testing'),
  });
}
  • optionsで指定したvus(バーチャルユーザー)が並列の実行数、iterationsが繰り返しの回数。これらの値はコマンド実行時の引数としても指定が可能。

  • check()で得られたレスポンスを検証する。

  • k6/httpパッケージからhttp.get()を実行する。

以下のようにして実行する。

k6 run script.js

出力値が得られる。

running (00m01.0s), 00/10 VUs, 10 complete and 0 interrupted iterations
default ✓ [================================] 10 VUs  00m01.0s/10m0s  10/10 shared iters 

     ✓ verify homepage text

     checks.........................: 100.00% ✓ 10        ✗ 0
     data_received..................: 173 kB  170 kB/s
     data_sent......................: 5.4 kB  5.3 kB/s
     http_req_blocked...............: avg=295.59ms min=189.1ms  med=294.41ms max=411.22ms p(90)=409.23ms p(95)=410.19ms
     http_req_connecting............: avg=182.76ms min=174.11ms med=184.7ms  max=190.56ms p(90)=187.51ms p(95)=189.21ms
     http_req_duration..............: avg=203.91ms min=180.19ms med=202.93ms max=227.96ms p(90)=222.8ms  p(95)=227ms
       { expected_response:true }...: avg=203.91ms min=180.19ms med=202.93ms max=227.96ms p(90)=222.8ms  p(95)=227ms
     http_req_failed................: 0.00%   ✓ 0         ✗ 20
     http_req_receiving.............: avg=1.12ms   min=0s       med=0s       max=16.71ms  p(90)=1.15ms   p(95)=3.18ms
     http_req_sending...............: avg=72.81µs  min=0s       med=0s       max=1.42ms 
  p(90)=18.2µs   p(95)=88.29µs
     http_req_tls_handshaking.......: avg=105.13ms min=0s       med=99.28ms  max=224.41ms p(90)=222.98ms p(95)=223.89ms
     http_req_waiting...............: avg=202.71ms min=179.18ms med=202.93ms max=227.96ms p(90)=220ms    p(95)=222.1ms
     http_reqs......................: 20      19.681399/s
     iteration_duration.............: avg=999.27ms min=980.82ms med=1s       max=1.01s  
  p(90)=1.01s    p(95)=1.01s
     iterations.....................: 10      9.8407/s
     vus............................: 7       min=7       max=7
     vus_max........................: 10      min=10      max=10

ここまでがhttpでの例。

k6/ws

k6でwebsocketを扱う時は、k6/wsパッケージを用いる。

http接続ではres = http.get('http://test.k6.io/');としてレスポンスを渡したのに対して、ws接続ではres = ws.connect()としてwsが接続してから切断するまでの処理を渡す。

import ws from 'k6/ws';

export default function () {
  const url = 'ws://echo.websocket.org';
  const res = ws.connect(url, null, function (socket) {
    socket.on('open', function () {
      console.log('WebSocket connection established!');
      socket.close();
    });

    socket.on("message", function (message) {
      const msg = JSON.parse(message);
      console.log(msg);
    });
  });

  console.log(res);
  check(res, { 'Connected successfully': (r) => r && r.status === 101 });
}

なお、この際にresとして得られる値はbodyの値を持たない。

console.log(res);
//{"url": "ws://echo.websocket.org","status":101,(略)"Connection":"upgrade","Upgrade":"WebSocket","Sec-Websocket-Accept":""},"body":"","error":""}

なのでbodyの値で検証といったことはできず、ステータスが101であるかを確認する程度となる。

check(res, { 'Connected successfully': (r) => r && r.status === 101 });

以下でメソッドの解説を行う。

connect

connectは

connect( url, params, callback )

と三つの引数を持つ。websocket接続の際にヘッダーやタグを設定する必要があれば、paramsに引き渡す。

なお、Connection, Upgrade, Sec-WebSocket-Keyといったwebsocket接続にそもそも必要なヘッダーはデフォルトで含まれているので入れる必要がない。

Socket.send(data)

send()でメッセージの送信を行う。

  const res = ws.connect(url, null, function (socket) {
    socket.on("open", function open() {
      const message = { hoge: "fuga" };
      socket.send(JSON.stringify(message));
    });
  }

Socket.setInterval(callback, interval)

setInterval()を使用する際はSocket.setInterval()を使用する。

定期的に送信を行うテストで使用できる。

  const res = ws.connect(url, params, function (socket) {
    socket.on('open', function open() {
      socket.setInterval(function timeout() {
        const message = { hoge: "fuga" };
        socket.send(JSON.stringify(message));
      }, 1000);
    });

Socket.setTimeout(callback, period)

setTimeoutを使用する際はSocket.setTimeoutを使用する。

    socket.setTimeout(function () {
      socket.close();
    }, 2000);

Socket.close()

socket.close();

接続を閉じる。これを実行するとws.connect()の処理が終了し、値が返却される。

実行方法

以下のようにして実行する。

k6 run script.js

出力値が得られる。

     data_received........: 4.1 kB 4.7 kB/s
     data_sent............: 197 B  226 B/s
     iteration_duration...: avg=869.59ms min=869.59ms med=869.59ms max=869.59ms p(90)=869.59ms p(95)=869.59ms
     iterations...........: 1      1.148347/s
     ws_connecting........: avg=869.14ms min=869.14ms med=869.14ms max=869.14ms p(90)=869.14ms p(95)=869.14ms
     ws_sessions..........: 1      1.148347/s
     ws_msgs_received......: 1    2/s
     ws_msgs_sent..........: 1    2/s
  • iteration_durationが実行にかかった時間
  • iterationsが繰り返した回数
  • ws_connectingがws接続に必要な時間
  • ws_msgs_receivedが受信したメッセージの数
  • ws_msgs_sentが送信したメッセージの数

なお、handleSummary関数を用いて出力値を変えることもできる。

とりあえず全部出力してみる。

// 終了時に実行される
export function handleSummary(data) {
  return data
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0