LoginSignup
30
15

More than 3 years have passed since last update.

WebSocket の負荷テストは Artillery でシュッと簡単に実行しよう

Posted at

Artillery は yaml ファイルに宣言的にシナリオを記述し、シンプルなインタフェースで負荷をかけることができる Nodejs 製の負荷テストツールです。
本記事では Artillery を使用して簡単に WebSocket サーバの負荷テストを実行する方法を紹介します。

最小構成の WebSocket サーバ

まずはじめに WebSocket サーバを実装しましょう。今回は Node.js を使用します。
必要最小限の機能だけを提供します。ws ライブラリを使用して簡単に実装しましょう。

server.js
const WebSocket = require("ws");

const wss = new WebSocket.Server({ port: 3000 }, () => {
  console.log("server is now listening localhost:3000");
});

let connections = [];

wss.on("connection", ws => {
  connections.push(ws);
  console.log(`new connection established. connections: ${connections.length}`);
  ws.on("close", () => {
    console.log(`connection closeed: ${connections.length}`);
    connections = connections.filter((conn, i) => conn !== ws);
  });
  ws.on("message", message => {
    broadcast(JSON.stringify(message));
  });
});

const broadcast = message => {
  connections.forEach((con, i) => {
    con.send(message);
  });
};

起動して以下のメッセージが表示されれば準備完了です。

$ node server.js
server is now listening localhost:3000

wscat で接続を確認する

サーバを起動したらまず wscat を使用して動作の確認をしましょう。wscat は npm でインストールできます。

$ npm install -g wscat

WebSocket サーバを起動し、wscat で接続したら任意のメッセージを送信してみましょう。1つのクライアントからの送信を受けて、他のクライアントへ broadcast していることがわかります。

wscat

Artillery を使用して負荷テストを実行する

さて、ようやく本題です。Artillery を使用して負荷テストをかけてみましょう。
最小限のシナリオファイルのサンプルです。シナリオファイルは senario.yml のような名前をつけておきます。

senario.yaml
config:
  target: "ws://localhost:3000"
  phases:
    - duration: 20
      arrivalRate: 10
scenarios:
  - engine: "ws"
    flow:
      - send: "hello"

以下、コマンドで実行します。

$ artillery run senario.yml

run

アクティブなコネクション数を調整する

実際に WebSocket を用いたアプリケーションでは、常に多くのコネクションが張られていることが一般的です。上記のシナリオでは hello というメッセージを送ったらすぐにコネクションを切断してしまうので、常時アクティブなコネクションが少ない状態であまり現実的ではありません。まずは、think を指定してアクティブなコネクション数が増えるように調整しましょう。また、同じメッセージを繰り返し送信する loop も指定できます。

senario.yaml
scenarios:
  - engine: "ws"
    flow:
      - send: "hello"
      - think: 1 # pause for 1 second
      - loop:
          - send: "world"
        count: 5

オブジェクトの送信に対応する

さて先ほどまでは string 形式のデータだけに限定していましたが、{"name":"john", "age":24} のようにオブジェクト形式で送信する方が良いこともあるでしょう。以下のように記述すれば、送信時に Stringify してくれます。

senario.yaml
scenarios:
  - engine: "ws"
    flow:
      # the following will be stringified and sent as '{"name":"john","age":24}'
      - send:
          name: "john"
          age: 24

カスタムコードを使用してタイムスタンプを付与する

また、送信したタイムスタンプを付与したいこともあります。このようなケースに対応するためにはカスタムコードを使用して柔軟に値を差し込むことができます。

senario.yaml
config:
  target: "ws://localhost:3000"
  processor: "./custom.js"
scenarios:
  - engine: "ws"
    flow:
      # custom code for timestanp
      - function: "createTimestampedObject"
      - send: "{{ data }}"

非常にシンプルに記述し、シュッと実装することができました。Artillery は WebSocket だけではなく、HTTPのプロトコルもサポートしています。本記事は公式ドキュメントから参照していますので、詳細に理解されたい方は一度ドキュメントに目を通してみるのも良いでしょう。

また、CircleCIで継続的に負荷テストを実行するTipsをこちらの記事で紹介していますのでぜひご参照ください。

30
15
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
30
15