K6
概要
今回は 性能測定用の負荷クライアントである K6 を紹介します。 K6は golang製の負荷テストツールとなります。特徴はシンプルで強力なところです。
K6はインストール、シナリオ記述、そして実行の各局面でサクッと進められるよう、とてもシンプルな仕様となっています。
性能試験でバタバタしている時に、仮に良いツールがあったとしても学習コストをかけていられないですよね?そんなユーザの心の声を汲んでかK6の習得は簡単です。
インストール
インストールの方法は3種類です。どれも簡単な手順で導入が可能です。
- パッケージマネージャ
- シングルバイナリ
- Docker イメージ
K6はCLIのツールなので、Homebrewや apt-get等のパッケージマネージャから落としてくることができます。
$ brew install k6
Mac (Homebrew) の場合これだけです。Linuxの場合は Debian系, RedHat系に応じて インストールすることができます。
また、k6は golang製ですので、シングルバイナリのファイルも GitHub上で提供されています。この場合ファイルを落としてきて実行するだけです。簡単ですね。
シナリオ定義
次にシナリオファイルです。シナリオファイルは JSで用意します。こんな感じ。
[basic-test.js]
import http from "k6/http"; import { check, sleep } from "k6"; export default function() { http.get("http://test.loadimpact.com"); };
実行
ここまでできたなら、一旦実行してみます。
$ k6 run basic-test.js
1リクエストだけ実行するサンプルができました。次に同じスクリプトを利用して2ユーザによる5秒間, 10rpsでのアクセスを試みます。この指定はスクリプト内での固定定義も可能ですし実行時の引数で動的に指定することも可能です。
$ k6 run -u 2 -d 5s --rps 10 basic-test.js
注意点
注意点として、一定の負荷を超えファイルディスクリプタが枯渇すると実行時にエラーが発生することがあります。 その際は OS上でファイルディスクリプタの最大値をチューニングすると収束します。
結果確認
結果が出力されたら内容を確認してみます。項目数が多いので面くらいますが、ポイントを抑えておけば大丈夫です。 Latencyが気になるなら http_req_duration を、Throughputなら data_received, data_sent を、そもそも全データを処理したかという点なら http_reqsを中心に確認します。
基本メトリクス
# | 分類 | 要素名 | 内容 | 観点 |
---|---|---|---|---|
1 | 設定 | execution | 実行環境 (基本は local) | (設定ログ) |
2 | 設定 | output | 出力先 | (設定ログ) |
3 | 設定 | script | シナリオスクリプト | (設定ログ) |
4 | 設定 | duration | 実行時間 | (設定ログ) |
5 | 設定 | iterations | JSの実行回数 | (設定ログ) |
6 | 設定 | vus | アクティブ仮想ユーザ数 | (設定ログ) |
7 | 設定 | max | 最大可能仮想ユーザ数 | (設定ログ) |
8 | - | done | プログレスバー | - |
9 | 結果 | data_received | 受信データの総量と秒間データ量 | N/Wが輻輳すると秒間転送率が低下 |
10 | 結果 | data_sent | 送信データの総量と秒間データ量 | N/Wが輻輳すると秒間転送率が低下 |
11 | 結果 | checks | check関数がある場合の結果 | - |
HTTP系メトリクス
# | 分類 | 要素名 | 内容 | 観点 |
---|---|---|---|---|
12 | 結果 | http_reqs | k6が生成した総リクエスト数 | 指定との乖離大は N/W・Server 遅延の可能性 |
13 | 結果 | http_req_blocked | 空きTCPコネクションの待ち時間 | TCPの接続プールは充分か |
14 | 結果 | http_req_looking_up | DNSの名前解決に費やした時間 | キャッシュは適切か |
15 | 結果 | http_req_tls_handshaking | TLSセッションのハンドシェイクに費やした時間 | 接続におけるTLSの負荷は高いか |
16 | 結果 | http_req_sending | リモートホストへのデータ送信にかかった時間 | 送信は遅くないか |
17 | 結果 | http_req_waiting | リモートホストからの応答待ちにかかった時間 (= TTFB) | サーバ処理は遅くないか |
18 | 結果 | http_req_receiving | リモートホストからのデータ受信にかかった時間 | 受信は遅くないか |
19 | 結果 | http_req_duration | リクエスト単体の合計時間 (sending + waiting + receiving) (接続・DNS lookupは含まない) | 全体で遅くないか |
(Option) レスポンスチェック
性能試験の結果に成功条件を盛り込みたい場合 check
関数を利用して実現することができます。
例えば つぎのスクリプトは 2種類のチェックを行っています。
- ステータスコードが 200 (成功) であること
- レスポンスタイムが 3秒 (3000ms) 以内であること
import { check } from "k6"; import http from "k6/http"; export default function() { let res = http.get("http://test.loadimpact.com/"); check(res, { "is status 200": (r) => r.status === 200, "duration < 3000ms": (r) => r.timings.duration < 3000 }); }
この様にして実行すると、実行結果上にチェックの結果も追記されます。
この際 ✓ 18
がOKで ✗ 0
がNGを意味します。日本と海外では ✓
の意味が逆だったりするので騙されないでください。
また、上記は全件OKですが、NGがある場合はチェック項目ごとに OK数と NG数が表示されます。
✓ status != 4xx ✓ status != 5xx ✗ duration < 3000ms ↳ 99% — ✓ 297 / ✗ 3
まとめ
- golang 利用で並列実行が強力
- 環境構築が楽ちん
- 実シナリオファイルは JavaScript という親切設計