継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

k6 でシナリオテストをやってみた

タダです.

API のリプレイスをしている中で負荷試験やシナリオ試験ができていなくて,そういったテストをできるようなツールとして k6 を同僚から教えてもらって試してみました.この記事で k6 を触ってみたので試したことなどまとめていきます.

k6 とは

k6JavaScript でかけるオープンソースの負荷テストツールです.特徴として次のようなものがあります.

  • CLI のテストツールであること
  • 後述しますが,負荷テストを行って確認項目をチェック表示したり,パーセンタイルで出せたりいろんなオプションがある
  • テストの結果を Grafana で可視化できること

k6.io

k6 の導入

k6 の導入は簡単で Mac なら以下のコマンド1発で終わります.

$ brew install k6

k6.io

k6 でテストを実行する

k6 でのテストを実行していきます.まずは Getting Started な内容で書いていきます.export default function ()の中で API を呼び出す順番だったり,条件を記述してシナリオを作っていきます.

import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  http.get('https://test.k6.io');
  sleep(1);
}

上記のテストを実行してみます.テストの実行は k6 run テストファイル名 で行います.

% k6 run test.ts 

          /\      |‾‾| /‾‾/   /‾‾/   
     /\  /  \     |  |/  /   /  /    
    /  \/    \    |     (   /   ‾‾\  
   /          \   |  |\  \ |  ()  | 
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: test.ts
     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 (00m01.3s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs  00m01.3s/10m0s  1/1 iters, 1 per VU

     data_received..................: 132 kB 105 kB/s
     data_sent......................: 516 B  411 B/s
     http_req_blocked...............: avg=198.22ms min=198.22ms med=198.22ms max=198.22ms p(90)=198.22ms p(95)=198.22ms
     http_req_connecting............: avg=8.85ms   min=8.85ms   med=8.85ms   max=8.85ms   p(90)=8.85ms   p(95)=8.85ms  
     http_req_duration..............: avg=51.22ms  min=51.22ms  med=51.22ms  max=51.22ms  p(90)=51.22ms  p(95)=51.22ms 
       { expected_response:true }...: avg=51.22ms  min=51.22ms  med=51.22ms  max=51.22ms  p(90)=51.22ms  p(95)=51.22ms 
     http_req_failed................: 0.00%  ✓ 01  
     http_req_receiving.............: avg=26.08ms  min=26.08ms  med=26.08ms  max=26.08ms  p(90)=26.08ms  p(95)=26.08ms 
     http_req_sending...............: avg=78µs     min=78µs     med=78µs     max=78µs     p(90)=78µs     p(95)=78µs    
     http_req_tls_handshaking.......: avg=172.55ms min=172.55ms med=172.55ms max=172.55ms p(90)=172.55ms p(95)=172.55ms
     http_req_waiting...............: avg=25.06ms  min=25.06ms  med=25.06ms  max=25.06ms  p(90)=25.06ms  p(95)=25.06ms 
     http_reqs......................: 1      0.796752/s
     iteration_duration.............: avg=1.25s    min=1.25s    med=1.25s    max=1.25s    p(90)=1.25s    p(95)=1.25s   
     iterations.....................: 1      0.796752/s
     vus............................: 1      min=1      max=1
     vus_max........................: 1      min=1      max=1

テスト実行後に表示されるアウトプットが多数表示されますが,それぞれの意義は次のとおりです.

表示名 説明
execution k6 の実行モードを表わし,local か cloud がある
output テストの結果がでるが,デフォルトは出力されない
script テストファイルのパス
scenarios テストシナリオの概要
data_received 受信したデータの量
data_sent 送信したデータの量
http_req_blocked リクエストを開始するまでにブロックされていた時間
http_req_connecting リモートホストとのTCP接続確立に要した時間
http_req_duration サーバーがリクエストを受け付けてからレスポンスを返すまでにかかった時間
http_req_failed リクエストの失敗割合
http_req_receiving サーバーからのレスポンスデータの受信にかかった時間
http_req_sending サーバーへのデータ送信にかかった時間
http_req_tls_handshaking サーバーとのTLSセッションのハンドシェイクにかかった時間
http_req_waiting サーバーからのレスポンスを待つ時間
http_reqs k6 が生成したHTTPリクエストの総数
iteration_duration テスト1回の反復処理に要した時間
iterations テストスクリプトを実行した回数の総計
vus アクティブな仮想ユーザー数
vus_max 最大の仮想ユーザー数

関連情報

k6.io k6.io

k6 のオプション

k6 ではテストを作っていく時に様々なオプションがあります.ここでは自分が使ってみてよく使いそうなものをまとめていきます.

ユーザーの増加

サービスを本番に載せたときに稼働状況からユーザーが段階的に増えることはよくあると思います.そんなケースを k6 で表現できます.以下のコードは最初はユーザー数5だけど,10秒ごとに30->50->80と target で指定した分,ユーザー数が段階的に増えるようなイメージです.

export let options = {
  scenarios: {
    'api_scenario': {
            executor: 'ramping-vus',
            startVUs: 5,
            stages: [
                { duration: '10s', target: 30},
                { duration: '10s', target: 50},
                { duration: '10s', target: 80},
                { duration: '10s', target: 110},
                { duration: '10s', target: 140},
                { duration: '10s', target: 170},
                { duration: '10s', target: 200}
            ],
            gracefulRampDown: '10s'
        }
    }

テスト結果のイメージとしては次のよう表示になり,api_scenario部分のパラメーターがどんどん増えるような動作をします.

running (1m20.0s), 000/200 VUs, 38 complete and 172 interrupted iterations
api_scenario ✓ [======================================] 170/200 VUs 

テストのサマリーを好みの表示にする

テスト結果をシステムの目標値,例えばレスポンスタイムの99パーセンタイルでみたら 0.5 秒以下になるかみたいなのをすぐに見れると楽ですよね? そういったテストの結果の表示をカスタマイズできます.

export let options = {
    summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(95)', 'p(99)', 'count'],
};

デフォルトですと'avg', 'min', 'med', 'max', 'p(95)'が表示されますが,更に追加で 'p(99)', 'count'を表示するようにしました.

     checks.........................: 100.00% ✓ 12510    
     data_received..................: 4.6 MB  51 kB/s
     data_sent......................: 385 kB  4.3 kB/s
   ✓ failed requests................: 0.00%   ✓ 01251 
     http_req_blocked...............: avg=6.38ms   min=0s      med=1µs     max=237.1ms  p(95)=33.8ms   p(99)=70.11ms  count=1251
     http_req_connecting............: avg=2.05ms   min=0s      med=0s      max=221.34ms p(95)=9.88ms   p(99)=16.56ms  count=1251
   ✓ http_req_duration..............: avg=88.12ms  min=23.63ms med=68.47ms max=1.87s    p(95)=151.46ms p(99)=420.5ms  count=1251
       { expected_response:true }...: avg=88.12ms  min=23.63ms med=68.47ms max=1.87s    p(95)=151.46ms p(99)=420.5ms  count=1251
     http_req_failed................: 0.00%   ✓ 01251 
     http_req_receiving.............: avg=174.17µs min=40µs    med=128µs   max=21.53ms  p(95)=348.5µs  p(99)=538µs    count=1251
     http_req_sending...............: avg=188.65µs min=24µs    med=166µs   max=973µs    p(95)=371µs    p(99)=525.5µs  count=1251
     http_req_tls_handshaking.......: avg=4.19ms   min=0s      med=0s      max=181.1ms  p(95)=23.69ms  p(99)=35.61ms count=1251
     http_req_waiting...............: avg=87.75ms  min=23.34ms med=68.05ms max=1.85s    p(95)=151.09ms p(99)=420.16ms count=1251
     http_reqs......................: 1251    13.89481/s
     iteration_duration.............: avg=1m28s    min=1m27s   med=1m28s   max=1m29s    p(95)=1m29s    p(99)=1m29s  count=6   
     iterations.....................: 6       0.066642/s
     vus............................: 71      min=5      max=99 
     vus_max........................: 100     min=100    max=100

テストの合格条件を定める

テストの合格条件を自分はこれまで目視でチェックしたり計算していましたが,k6 では合格条件の数値を指定してそれをチェックできます.例えば,次のコードでは k6 の結果で出てくる項目の failed requestshttp_req_duration で合格条件をチェックするようにしています.条件としては次のようなもの意図して設定しています.

  • エラー率が1%未満
  • レスポンスタイムが99%タイルで500ms以下
export let options = {
  thresholds: {
    'failed requests': ['rate<0.01'], 
    'http_req_duration': ['p(99)<500'] 
  },
};

関連情報

k6.io

k6.io

k6.io

まとめ

k6 の概要,導入,テスト実行,オプションをの簡単な紹介を記事にまとめました.テストでチェックしたい合格基準の閾値を設定すれば,そのチェックをしてくれたり実際の利用シーンのようなユーザー数の増加も調整できたりと,使ってみてよかったです.本番に乗せる前に API の機能でどれくらいパフォーマンスが出て,目標値に達していそうかがわかるのが良かったので,気になる方は使うきっかけになれば嬉しいです!