負荷試験ツール"k6"の導入から実行まで

# 概要
この記事は、負荷試験ツール"k6"の導入から実行までを説明したものです。
自身の備忘録、他の人への説明を主な目的とした内容になっています。

# 前提
ローカルマシンOS: Ubuntu 22(Window 11 WSL)

# k6とは
k6はオープンソースの負荷試験ツールです。Go言語によって作成されており、軽量・ハイパフォーマンスを謳っています。
オープンソース版は、テストの実行をCLIにて行うため、ある程度コンソール画面での操作の習熟を求められます。
私は使っていないのですが、テストシナリオの作成についてはGUIが提供されているようです。ただ、JavaScriptのコードで管理するほうが共有や運用が楽かと思います。

# 導入
https://grafana.com/docs/k6/latest/set-up/install-k6/

Windows/Mac/Linux各種環境に応じたインストール方法が提供されています。
自分の場合はUbuntuのため、リポジトリを追加してパッケージインストールを行いました。

# テストシナリオの作成
https://grafana.com/docs/k6/latest/get-started/running-k6/

インストール後、下記のコマンドを実行することで、雛形となるテストシナリオのファイル`script.js`が作成されます。
``` bash
$ k6 new
```

VSCodeなどのエディタ向けに拡張機能も公開されているので、生成されたテストシナリオの編集なども容易に行えると思います。

`new`で出力されるファイルの中身を見れば、特定URLに対するGETでのテストは容易に作成できるかと思います。
自分が使用するときはPOSTでのアクセスが必要だったのですが、公式のドキュメントが充実しているため、それほど苦労はしませんでした。例として内容を変えて記載しておきます。

#### 例: POSTでのアクセス
``` javascript:script.js
export default function() {
  const url = 'https://post.url';
  const list = [
    "param_a",
  ];
  // listの中身をランダムに送信
  const payload = JSON.stringify({
	  item: list[Math.floor(Math.random() * list.length)],
  });
  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };
  const res = http.post(url, payload, params);
  ～省略～
}
``` 

https://grafana.com/docs/k6/latest/javascript-api/

# 実行
以下のコマンドで作成したテストシナリオに基づいてテストを実行します。
``` bash
$ k6 run script.js
```
負荷試験の各アクセスの詳細データを取得したい場合は、`--out`オプションを付けて実行することで、出力できます。
``` bash
$ k6 --out csv=test_e2.csv run script.js
```
実際に上記コマンドでテストを実行した際には、インジケーターで進捗が表示された後、下記の画像のような結果画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274706/7013a84e-35f5-305c-7b4e-15b9ecec9f3d.png)

他にもオプションを指定することで、Virtual Users(並列接続数 以下vus)や、Duration(実行期間)を設定できます。
コマンドで指定しない場合、テストシナリオのスクリプトに記載されているvusとdurationがデフォルトの値として使用されます。
オプションの使用例として、以下は公式サイトのドキュメントより抜粋したものですが、vusを10に、durationを30秒にした内容です。
``` bash
$ k6 run --vus 10 --duration 30s script.js
```


# 結果の見方
k6にはあらかじめ組み込みのメトリクスが豊富に存在します。

https://grafana.com/docs/k6/latest/using-k6/metrics/reference/

組み込み以外のメトリクスもシナリオファイルにJavaScriptで容易に記述することが可能です。

https://grafana.com/docs/k6/latest/using-k6/metrics/create-custom-metrics/

私の場合、Webツールの負荷試験でしたので、200レスポンスが返ってくることのチェックを追加しました。
``` javascript:script.js
export default function() {
  ～省略～
  check(res, {
    'status is 200': (r) => r.status === 200,
  });
  ～省略～
}
``` 

全てではありませんが、メトリクスの内容について記載します。

|項目名|意味| 
|---|---|
|checks|チェックに成功した割合|
|data_received|受信したデータの総量|
|data_sent|送信したデータの総量|
|http_req_blocked|リクエストを開始する前にブロックされていた時間(TCPコネクションスロットの空き待ち)|
|http_req_connecting|リモート・ホストとのTCP接続の確立にかかった時間|
|http_req_duration|リクエストの合計時間。これはhttp_req_sending + http_req_waiting + http_req_receiving(最初のDNSルックアップ/接続時間を除いた、リクエストの処理と応答にかかったリモートサーバーの時間) と等しい|
|http_req_failed|setResponseCallback に従って失敗したリクエストの割合|
|http_req_receiving|リモートホストから応答データを受信している時間|
|http_req_sending|リモートホストへのデータ送信にかかった時間|
|http_req_tls_handshaking|リモートホストとのTLSセッションのハンドシェイクにかかった時間|
|http_req_waiting|リモートホストからの応答を待っている時間（別名「time to first byte」、「TTFB」）|
|http_reqs|k6が生成したHTTPリクエストの総数|
|iteration_duration|１回の反復処理に費やされた時間|
|iterations|反復処理の回数|
|vus|現在の仮想ユーザ数|
|vus_max|仮想ユーザの最大可能数|

トレンドタイプの結果の見方は以下です。
- avgは平均
- minは最小値
- maxは最大値
- medは中央値
- p(N)は特定のパーセンタイル。Nは 0.0から 100.0の間の数値で、見るべきパーセンタイルの値を意味する。例えばp(99.99)は99.99パーセンタイルを意味する。

# さいごに
負荷試験ツールとして定番ともいえるJMeterは、導入やテストシナリオの作成のハードルが少しあるため、気軽に導入・使用のできるk6はおすすめできるツールだと感じました。

余談ですが、k6は、オープンソース版とは別に、クラウドサービスとしても提供されています。
使える機能に違いあったり、クラウド版にはグラフィカルな分析ツールが提供されているので、規模や目的に合わせて選択肢になり得るかと思います。

https://k6.io/oss-vs-cloud/