負荷テストツール「K6」を使って、アプリケーションのパフォーマンスを効率的にテストする方法を解説します。本記事では、インストール方法から基本構文テスト実行まで、実践的な使い方を紹介します。

この記事の概要

  1. K6のインストール方法
  2. テストの基本と実行
  3. テストファイルの作成方法
  4. メトリクスとオプション設定
  5. Thresholds(しきい値)の設定と使い方
  6. テストライフサイクル

1. インストール

・Homebrew(macOS/Linux)

brew install k6

・Docker

docker pull grafana/k6

・Windows

Chocolateyまたは公式サイトからインストール可能。


2. テスト実行の基本

・テンプレートでテストファイルを作成する

k6 new

k6 new コマンドでテストファイルのテンプレートを作成することができます。
k6 new <ファイル名> と指定することで、ファイル名を指定してテンプレートを作成することもできます。

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

export const options = {
  // A number specifying the number of VUs to run concurrently.
  vus: 10,
  // A string specifying the total duration of the test run.
  duration: '30s',

  // The following section contains configuration options for execution of this
  // test script in Grafana Cloud.
  //
  // See https://grafana.com/docs/grafana-cloud/k6/get-started/run-cloud-tests-from-the-cli/
  // to learn about authoring and running k6 test scripts in Grafana k6 Cloud.
  //
  // ext: {
  //   loadimpact: {
  //     // The ID of the project to which the test is assigned in the k6 Cloud UI.
  //     // By default tests are executed in default project.
  //     projectID: "",
  //     // The name of the test in the k6 Cloud UI.
  //     // Test runs with the same name will be grouped.
  //     name: "hoge.js"
  //   }
  // },

  // Uncomment this section to enable the use of Browser API in your tests.
  //
  // See https://grafana.com/docs/k6/latest/using-k6-browser/running-browser-tests/ to learn more
  // about using Browser API in your test scripts.
  //
  // scenarios: {
  //   // The scenario name appears in the result summary, tags, and so on.
  //   // You can give the scenario any name, as long as each name in the script is unique.
  //   ui: {
  //     // Executor is a mandatory parameter for browser-based tests.
  //     // Shared iterations in this case tells k6 to reuse VUs to execute iterations.
  //     //
  //     // See https://grafana.com/docs/k6/latest/using-k6/scenarios/executors/ for other executor types.
  //     executor: 'shared-iterations',
  //     options: {
  //       browser: {
  //         // This is a mandatory parameter that instructs k6 to launch and
  //         // connect to a chromium-based browser, and use it to run UI-based
  //         // tests.
  //         type: 'chromium',
  //       },
  //     },
  //   },
  // }
};

// The function that defines VU logic.
//
// See https://grafana.com/docs/k6/latest/examples/get-started-with-k6/ to learn more
// about authoring k6 scripts.
//
export default function() {
  http.get('https://test.k6.io');
  sleep(1);
}

テストスクリプトはJavaScript形式で記述します。以下は基本構文です。

テストファイルの基本構文

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

export let options = {
  vus: 10,  // 仮想ユーザー数
  duration: '30s',  // 実行時間
};

export default function () {
  let response = http.get('https://example.com');
  check(response, { 'status is 200': (r) => r.status === 200 });
  sleep(1);
}
  • vus: 仮想ユーザー数(Virtual Users)。同時にリクエストを実行する数。ここでは10人のユーザーがアクセスをシミュレーションします。
  • duration: テストの継続時間。30秒間、リクエストを送り続けます。
  • http.get('https://example.com'): 指定URLにGETリクエストを送信します。response変数に結果が格納されます。
  • check(response, { 'status is 200': (r) => r.status === 200 }): レスポンスステータスが200(成功)であることを確認します。条件が満たされれば成功、満たされない場合は失敗として記録されます。
  • sleep(1): 1秒の遅延を挿入し、負荷を均等に分散します。

テストの実行
以下のコマンドでテストを実行することができる。

k6 run test-script.js 

3. 実行オプション

オプション説明
vus仮想ユーザー数
durationテスト実行の継続時間
iterationsリクエストの実行回数

4. メトリクスの見方

実行結果には、http_req_durationhttp_req_failedなどの詳細なメトリクスが表示されます。
詳細は公式のmetricsのページをご覧ください。

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

  execution: local
     script: test.js
     output: -

  scenarios: (100.00%) 1 scenario, 10 max VUs, 1m0s max duration (incl. graceful stop):
           * default: 10 looping VUs for 30s (gracefulStop: 30s)
	   
     data_received..................: 3.0 MB 96 kB/s
     data_sent......................: 28 kB  911 B/s
     http_req_blocked...............: avg=17.47ms  min=2µs      med=5µs      max=457.81ms p(90)=8µs      p(95)=24.69µs 
     http_req_connecting............: avg=6.87ms   min=0s       med=0s       max=182.71ms p(90)=0s       p(95)=0s      
     http_req_duration..............: avg=182.93ms min=174.29ms med=176.02ms max=349.4ms  p(90)=177.33ms p(95)=178.13ms
       { expected_response:true }...: avg=182.93ms min=174.29ms med=176.02ms max=349.4ms  p(90)=177.33ms p(95)=178.13ms
     http_req_failed................: 0.00%  ✓ 0        ✗ 254 
     http_req_receiving.............: avg=6.91ms   min=32µs     med=70.5µs   max=173.03ms p(90)=355µs    p(95)=628.79µs
     http_req_sending...............: avg=26.9µs   min=9µs      med=20µs     max=684µs    p(90)=35µs     p(95)=40µs    
     http_req_tls_handshaking.......: avg=8.05ms   min=0s       med=0s       max=216.55ms p(90)=0s       p(95)=0s      
     http_req_waiting...............: avg=175.99ms min=173.46ms med=175.82ms max=196.98ms p(90)=176.9ms  p(95)=177.23ms
     http_reqs......................: 254    8.180674/s
     iteration_duration.............: avg=1.2s     min=1.17s    med=1.17s    max=1.63s    p(90)=1.17s    p(95)=1.34s   
     iterations.....................: 254    8.180674/s
     vus............................: 4      min=4      max=10
     vus_max........................: 10     min=10     max=10


running (0m31.0s), 00/10 VUs, 254 complete and 0 interrupted iterations
default ✓ [======================================] 10 VUs  30s
メトリック名説明
data_received受信したデータの量
data_sent送信されたデータ量
http_req_blockedリクエストを開始するまでにブロック(TCPコネクションスロットの空き待ち)された時間
http_req_connectingリモートホストとのTCPコネクション確立に要した時間
http_req_durationリクエストの合計時間(http_req_sending + http_req_waiting + http_req_receiving)
http_req_failed失敗したリクエストの割合
http_req_receivingリモートホストからの応答データ受信に要した時間
http_req_sendingリモートホストへのデータ送信に費やした時間
http_req_tls_handshakingリモートホストとのTLSセッションのハンドシェイクに費やした時間
http_req_waitingリモートホストからの応答待ち時間(time to first byte TTFBとも呼ばれる)
http_reqshttpリクエストの総数
iteration_duration1回のイテレーションの実行に要した時間
iterationsvus(仮想ユーザー)が実行したデフォルト関数の回数
vusvirtual usersの略 同時にアクセスする仮想ユーザー数
vus_max仮想ユーザーの最大可能数

成功の判断基準

  • チェックの合格率 (checks) が100%である。
  • 失敗リクエスト (http_req_failed) が0%。
  • 設定したしきい値 (thresholds) を超えない応答時間。

5. CheckとThresholds

Checkはテスト条件の成功/失敗を定義し、Thresholdsで基準値を指定できます。

export let options = {
  thresholds: {
    'http_req_duration{p(95)}': ['<500'],  // 95%のリクエストが500ms以内
  },
};

6. テストライフサイクル

ここでは、k6のテストライフサイクルについて説明します。
k6には、次の4つのライフサイクルステージが存在します。

ステージ目的
initテストの開始前に一度だけ実行されるステージです。グローバル変数の宣言やテスト全体で使用する設定の初期化などを行います。
setupテストのdefault関数(VU code)が実行される前に一度だけ実行されるステージです。テストデータの準備や外部からのデータの取り込みなど、テスト実行に必要な前処理を行います。
VU Code各VU(仮想ユーザー)によって実行されるメインのテストスクリプトです。HTTPリクエストの送信やカスタムメトリクスの計測など、テストの核となるアクションが含まれます。
teardownテストのメイン部分の実行が終了した後に一度だけ実行されるステージです。テストで使用したリソースのクリーンアップや結果の後処理などを行います。

ライフサイクルは次のように関数で定義します。

// 1. init: 関数外のスコープは全てinitになる

export function setup() {
  // 2. setup: テスト実行(`k6 run`)1回につき1度テスト実行前に呼び出される
}

export default function() {
  // 3. VU code: 実際のテストシナリオ
}

export function teardown() {
  // 4. teardown code: テスト実行(`k6 run`)1回につき1度テスト実行後に呼び出される
}

まとめ

K6は、シンプルかつ強力な負荷テストツールです。スクリプト作成の柔軟性と、Thresholdsを活用した基準設定により、リアルな負荷シミュレーションを実現します。CI/CD環境に統合し、継続的なパフォーマンステストを行いましょう。

【その他技術ブログ】
正常系テストと異常系テストの違い、必要性について解説【初心者】
React におけるインテグレーションテストの重要性を調べてみた
[AWS EC2]Amazon Linux2023にcomposerをインストールする
シンギュラリティとは?未来社会を変える「技術的特異点」を解説
Git 高度な使い方:プロジェクト管理を一段階上へ