JavaScriptを有効にしてください

負荷試験ツールとしてk6を利用する

 ·  ☕ 4 分で読めます

SheepMedical では負荷試験ツールとして k6 を利用しています。

k6 は Grafana Labs がオープンソースで開発している負荷試験ツールで下記のような特徴があります。

  • Javascript でスクリプトを作成することができる
  • Go で作成されているため、バイナリを置くだけで、利用することができる
  • 負荷試験結果を様々なフォーマットで export できる
  • SaaS も用意されており、複数リージョンから実行したい場合などに、ローカルで作成したスクリプトをクラウドで実行することができる

簡易に利用できることや、特に別途 DSL を覚える必要がなく、JS でスクリプトを作成できることから採用しました。

インストール

各種環境用にパッケージが用意されているため、簡単にインストールすることができます。

Github のリリースページにバイナリがありますので、下記のように負荷試験環境にバイナリを落としてくるだけでも利用できます。

1
2
$ curl -OL https://github.com/grafana/k6/releases/download/v0.39.0/k6-v0.39.0-macos-arm64.zip
$ tar xvzf k6-v0.39.0-macos-arm64.zip

実行

前述のように、スクリプトは JS で書くことができます。

1
2
3
4
5
6
7
import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  http.get('http://localhost:8080');
  sleep(1);
}

実行は作成した JS ファイルを指定するだけです。

1
$ k6 run script.js

k6 では並列度として、VUs (Virtual Users)があります。実行時に指定することができます。

1
$ k6 run script.js --vus 10

負荷実行期間は Duration で指定可能です。

1
$ k6 run script.js --duration 30s

上記2つはスクリプト内でも指定可能です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import http from 'k6/http';
import { sleep } from 'k6';

export const options = {
  vus: 10,
  duration: '30s',
};

export default function () {
  http.get('http://localhost:8080');
  sleep(1);
}

基本的な構造

スクリプトは下記のような構造を持っています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export function setup() {
// 起動時に一回だけ実行される
};

export default function(tokens) {
// 実行期間中に繰り返し実行される
};

export function teardown() {
// 終了時に実行される
};

実行には少なくとも defaultが export されている必要があります。
setup に前処理を記載し、default には負荷試験内容、teardown に後処理を記載する形になります。

負荷試験結果

スクリプトを実行すると通常は stdout に結果が表示されます。(ドキュメントより)

k6 result

out オプションにより様々なフォーマットでエクスポートできます。

1
$ k6 run --out statsd script.js

出力できるタイプの一覧はドキュメントに記載があります。

またスクリプト内に handleSummary を定義することで出力する内容をカスタマイズすることができます。

SheepMedical では結果を HTML レポートとして参照したいため、 k6-reporter を利用してカスタマイズしています。

1
2
3
4
5
6
export function handleSummary(data) {
    return {
      'stdout': textSummary(data, { indent: ' ', enableColors: true }),
      "summary.html": htmlReport(data)
    };
};

シナリオ

Ramping up しながら、徐々に負荷を増やしていきたいケースなどあると思います。

k6 では executor という形で様々なシナリオを実現できます。

シナリオは option で指定します。例として、Warm up する場合は下記のような形になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//warmup/ramp testの並列度、実行時間の設定
export let options = {
    scenarios: {
        ramping_up_scenario: {
            executor: 'ramping-vus',

            startVUs:1,
            // 1 並列実行60s
            // target count 実行 rampup秒
            // target count実行 target秒
            stages: [
              {duration: '60s', target: 1},
              {duration: config.RAMPUP_DURATION, target: config.TARGET_PARALLELISM_COUNT},
              {duration: config.TARGET_DURATION, target: config.TARGET_PARALLELISM_COUNT},
            ]
        }
    }
};

ファイルからデータ読み込み

User の ID/PASS を事前に用意しておき、それらを利用して、認証してからリクエストを送りたい場合があると思います。

k6 では JS でスクリプトが記載できるので、このようなケースでも簡単に実現できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//jsonファイルから、userとpasswordを取得
const user_data_from_file = new SharedArray('user_data', function () {
    return JSON.parse(open('./user_data.json')).users;
});

let tokens = [];

export function setup() {
    //実行開始時にtokenを取得
    user_data_from_file.forEach(user => {
        // id/passからtokenを取得するget_tokenを別途定義しておく
        const token = get_token(user.username, user.password);
        tokens.push(token);
        sleep(2);
    });
    return tokens;
};

export default function(tokens) {

    //tokenをランダムに取得
    const token = tokens[Math.floor(Math.random() * tokens.length)];
    ...

};

まとめ

使ってみた印象としては、負荷試験に必要な機能が揃っており、また主力結果などをカスタマイズできるため、柔軟に様々なことを実現できるために、非常に使いやすいと感じました。
別途 DSL を覚える必要がないところも嬉しい点ですね。

またドキュメントも充実しており、ほとんどの問題がドキュメントを参照することで解決できました。

最後に

SheepMedical では負荷試験などを通じて、プロダクトの信頼性向上に興味がある方を絶賛募集しています。

共有

Shinichi Morimoto
著者
Shinichi Morimoto
Software Developer