TECHSCORE BLOG

クラウドCRMを提供するシナジーマーケティングのエンジニアブログです。

k6 のすすめ

ここしばらく、業務で負荷テストを行う際に 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 で実行回数、-uVU(スクリプトの実行単位)の数を調整できます。

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 の紹介でした。動かすまでにかかる手間が少ないツールなので、まずは試しに使ってみてはいかがでしょうか。

シナジーマーケティング株式会社では一緒に働く仲間を募集しています。