ここしばらく、業務で負荷テストを行う際に k6 というツールを使用しています。手軽で使い勝手も良いツールなので、今回は k6 の紹介記事を書くことにしました。
k6 とは
k6 はオープンソースの負荷テストのツールです(公式ページはこちら)。Go 製の CLI ツールで、テストケースを JavaScript で記述できるところが大きな特徴です。CLI は OSS ですが、実行環境やテスト結果のビジュアライゼーション・分析などが付いた有償の Cloud サービスもあります。
使ってみる
k6 がどのようなものか、その使用感を掴むためにも、シンプルなテストケースを試してみましょう。
テストケースを実行するにあたり、まずは k6 の CLI をインストールします。インストール方法としては、GitHub のリリースページからビルド済みのバイナリを取得できるほか、Mac の場合は Homebrew でインストールでき、Docker Hub にコンテナイメージもあります。記事執筆時点での最新バージョンは v0.39.0 なので、以降の内容はそのバージョンに準拠した内容になります。
いずれかの方法で k6 の CLI が実行できる環境が準備できたら、テストケースとして以下の JavaScript のファイルを作成します。
import http from "k6/http"; // 最低限、エクスポートされた default 関数が必要 export default function() { // リクエストを送り負荷をかけたいエンドポイントを記述 // ここではローカルに nginx を起動して実施 http.get("http://localhost:8080"); }
ファイルを作成したら、CLI でテストを実行します。
k6 run script.js
オプションを何も設定していない場合、以下のように、1件だけリクエストが送られ、実行結果が出力されます。
/\ |‾‾| /‾‾/ /‾‾/ /\ / \ | |/ / / / / \/ \ | ( / ‾‾\ / \ | |\ \ | (‾) | / __________ \ |__| \__\ \_____/ .io execution: local script: script.js output: - scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop): * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s) running (00m00.0s), 0/1 VUs, 1 complete and 0 interrupted iterations default ✓ [======================================] 1 VUs 00m00.0s/10m0s 1/1 iters, 1 per VU data_received..................: 853 B 74 kB/s data_sent......................: 80 B 6.9 kB/s http_req_blocked...............: avg=468µs min=468µs med=468µs max=468µs p(90)=468µs p(95)=468µs http_req_connecting............: avg=154µs min=154µs med=154µs max=154µs p(90)=154µs p(95)=154µs http_req_duration..............: avg=9.81ms min=9.81ms med=9.81ms max=9.81ms p(90)=9.81ms p(95)=9.81ms { expected_response:true }...: avg=9.81ms min=9.81ms med=9.81ms max=9.81ms p(90)=9.81ms p(95)=9.81ms http_req_failed................: 0.00% ✓ 0 ✗ 1 http_req_receiving.............: avg=893µs min=893µs med=893µs max=893µs p(90)=893µs p(95)=893µs http_req_sending...............: avg=92µs min=92µs med=92µs max=92µs p(90)=92µs p(95)=92µs http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s http_req_waiting...............: avg=8.83ms min=8.83ms med=8.83ms max=8.83ms p(90)=8.83ms p(95)=8.83ms http_reqs......................: 1 86.281277/s iteration_duration.............: avg=10.46ms min=10.46ms med=10.46ms max=10.46ms p(90)=10.46ms p(95)=10.46ms iterations.....................: 1 86.281277/s
k6 では、リクエストにかかった時間の平均値・最小値・中央値・最大値・パーセンタイルなどのメトリクスがデフォルトで取得され、実行結果として出力されます。上記の出力内容から、リクエストを1件送り、レスポンスが返ってくるまでに 8.83 ミリ秒かかったことなどが読み解けます。(個々のメトリクスの詳細についてはドキュメントをご参照ください)。
では、実行条件を変えて、もう少し負荷をかけてみます。実行回数や並列数を指定するのはコード上でもできますが、ここでは CLI のオプションに指定して実施してみます。-i
で実行回数、-u
で VU(スクリプトの実行単位)の数を調整できます。
k6 run -i 100 -u 10 script.js
これで、10個の VU で合計100回リクエストが実行されることになります。実行結果は以下の通りです。
/\ |‾‾| /‾‾/ /‾‾/ /\ / \ | |/ / / / / \/ \ | ( / ‾‾\ / \ | |\ \ | (‾) | / __________ \ |__| \__\ \_____/ .io execution: local script: script.js output: - scenarios: (100.00%) 1 scenario, 10 max VUs, 10m30s max duration (incl. graceful stop): * default: 100 iterations shared among 10 VUs (maxDuration: 10m0s, gracefulStop: 30s) running (00m00.2s), 00/10 VUs, 100 complete and 0 interrupted iterations default ✓ [======================================] 10 VUs 00m00.2s/10m0s 100/100 shared iters data_received..................: 85 kB 495 kB/s data_sent......................: 8.0 kB 46 kB/s http_req_blocked...............: avg=71.85µs min=1µs med=3µs max=923µs p(90)=71.7µs p(95)=649.74µs http_req_connecting............: avg=28.37µs min=0s med=0s max=440µs p(90)=20µs p(95)=265.75µs http_req_duration..............: avg=16.41ms min=2.17ms med=16.39ms max=52.58ms p(90)=23.45ms p(95)=30.11ms { expected_response:true }...: avg=16.41ms min=2.17ms med=16.39ms max=52.58ms p(90)=23.45ms p(95)=30.11ms http_req_failed................: 0.00% ✓ 0 ✗ 100 http_req_receiving.............: avg=53.91µs min=26µs med=48µs max=226µs p(90)=80.2µs p(95)=88.29µs http_req_sending...............: avg=20.47µs min=7µs med=14µs max=126µs p(90)=42.6µs p(95)=68.69µs http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s http_req_waiting...............: avg=16.34ms min=2.11ms med=16.3ms max=52.54ms p(90)=23.39ms p(95)=30.06ms http_reqs......................: 100 580.433584/s iteration_duration.............: avg=16.57ms min=2.24ms med=16.47ms max=52.64ms p(90)=23.55ms p(95)=30.17ms iterations.....................: 100 580.433584/s
このように、簡単に負荷をかけて、実行結果のメトリクスを取得することができます。今回は使用感のイメージを掴むために単純なケースを試しましたが、k6 に組み込まれている機能を利用すれば、より複雑なシナリオを組んでテストを行うこともできます。
k6 で重宝している点
上記のテストケースの実行により、k6 がどういうものかイメージが掴めたかと思います。最後に、私が k6 を使う上で重宝している点についてまとめておきます。
テストケースを JavaScript で記述できること
まず、JavaScript でテストケースを記述できるということは大きなポイントと言えます。学習コストもそこまでかからないですし、コードでテストケースを一通り完結させることができるので管理も容易です。また、豊富な JavaScript API が用意されており、さまざまなテストケースを実現することができるようになっています。
実行のしやすさ
上記で試した通り、テストの実行までに必要なステップが多くなく、迷う要素も少ないため、実行しやすい点も気に入っています。Go 製の CLI でシングルバイナリで実行できるので、さまざまな環境で手軽に実行できる点も重宝します。
ドキュメント・サンプルコードの充実
公式のドキュメントは k6 が持っている機能について詳細にまとめられており、より凝ったテストケースを作成する際に役に立ちます。また、さまざまなテストケースのサンプルコードが掲載されているのもありがたい点です。例えば、Cookie を扱うサンプルコードが掲載されているので、Cookie を介した認証などのテストケースを書く際に有益だったりします。
おわりに
以上、k6 の紹介でした。動かすまでにかかる手間が少ないツールなので、まずは試しに使ってみてはいかがでしょうか。