こんにちは。よっしーです(^^)
今日は、k6におけるtagとgroupについてご紹介します。
背景
Dockerで構築したWebアプリの開発環境において、k6のtagとgroupについて調査したときの内容を備忘として残しました。
開発環境のソースは下記のリポジトリにあります。
タグとグループ
通常、負荷テストは異なるサブシステムやリソースを持つサービスを対象とします。これにより、パフォーマンスを低下させる問題を特定するのが難しい場合があります。
k6は、テストの結果に以下の機能を追加して、テスト結果を視覚化、ソート、フィルタリングするのに役立ちます。
- タグは、詳細なフィルタリングのために、チェック、閾値、カスタムメトリクス、およびリクエストをカテゴライズします。
- グループは、スクリプトの関数にタグを適用します。
- これらの細かいタグに加えて、テスト全体のタグを設定するオプションも使用できます。これらのタグを使用して、複数のテストからの結果を比較することができます。
結果をフィルタリングするだけでなく、タグを使用して閾値の分析に適用する操作を制限することもできます。
タグ
タグは、k6エンティティをカテゴライズし、テスト結果をフィルタリングする強力な方法です。
k6は、次の2つのタイプのタグを提供しています。
- システムタグ:k6が自動的に割り当てるタグ
- ユーザー定義のタグ:スクリプトを作成する際に追加するタグ
システムタグ
現在、k6はデフォルトで以下のタグを自動的に作成します:
- proto 使用されたプロトコルの名前(例:HTTP/1.1)
- subproto WebSocketで使用されるサブプロトコルの名前
- status HTTPステータスコード(例:200、404など)
- method HTTPメソッド名(例:GET、POSTなど)またはgRPCのRPCメソッド名
- url HTTPリクエストのURL
- name HTTPリクエストの名前
- group 詳細については前述の説明を参照してくださいが、フルグループパス
- check Checkの名前
- error 非HTTPエラーメッセージを含む文字列(例:ネットワークエラーやDNSエラー)
- error_code エラータイプを指定する番号;現在のエラーコードのリストはエラーコードページで確認できます
- tls_version TLSバージョン
- scenario メトリックが発行されたシナリオの名前
- service gRPCのRPCサービス名
- expected_response responseCallbackに基づいてtrueまたはfalse(デフォルトではステータスが2xxまたは3xxであるかどうかをチェック)
前述のいくつかのタグを無効にするには、systemTagsオプションを使用してください。ただし、一部のデータ収集ツール(たとえばクラウドラン)では、特定のタグが必要とされる場合があります。
以下のシステムタグはオプションです。必要に応じて有効にしてください:
- vu リクエストを実行した仮想ユーザーのID
- iter 反復回数
- ip リモートサーバーのIPアドレス
- ocsp_status オンライン証明書ステータスプロトコル(OCSP)HTTPSステータス
ユーザー定義のタグ
テストのロジックに基づいて、k6エンティティをカテゴライズするために独自のタグを定義できます。以下のエンティティにタグを付けることができます:
- リクエスト
- チェック
- 閾値
- カスタムメトリクス
import http from 'k6/http';
import { Trend } from 'k6/metrics';
import { check } from 'k6';
const myTrend = new Trend('my_trend');
export default function () {
// Add tag to request metric data
const res = http.get('https://httpbin.test.k6.io/', {
tags: {
my_tag: "I'm a tag",
},
});
// Add tag to check
check(res, { 'status is 200': (r) => r.status === 200 }, { my_tag: "I'm a tag" });
// Add tag to custom metric
myTrend.add(res.timings.connecting, { my_tag: "I'm a tag" });
}
テスト全体のタグ
リクエスト、チェック、およびカスタムメトリクスにタグを添付するだけでなく、すべてのメトリクス全体に対してテスト全体のタグを設定できます。これらのタグを設定する方法は次の2つです:
- CLIを使用して、–tag NAME=VALUE フラグを1つ以上使用する方法
- スクリプト自体で次のように設定する方法:
export const options = {
tags: {
name: 'value',
},
};
コードで定義されたタグ
ユーザーがタグを設定するために高度なロジックが必要な場合、コードからタグを定義することが可能です。
高度なタグ付けワークフローをサポートするために、スクリプトのコードから直接タグを設定および取得することも可能です。
k6/execution.vu.tags オブジェクトのプロパティには、新しいキー/値ペアを動的に定義するために直接割り当てることができます。次の例で示すように、これは入れ子のグループからコンテナのグループを追跡し、入れ子のグループのサブメトリクスを集計するために便利です。
import http from 'k6/http';
import exec from 'k6/execution';
import { group } from 'k6';
export const options = {
thresholds: {
'http_reqs{container_group:main}': ['count==3'],
'http_req_duration{container_group:main}': ['max<1000'],
},
};
export default function () {
exec.vu.tags.containerGroup = 'main';
group('main', function () {
http.get('https://test.k6.io');
group('sub', function () {
http.get('https://httpbin.test.k6.io/anything');
});
http.get('https://test-api.k6.io');
});
delete exec.vu.tags.containerGroup;
http.get('https://httpbin.test.k6.io/delay/3');
}
同じAPIを使用して、すでに設定されているユーザー定義またはシステム定義のタグを取得することもできます。
import exec from 'k6/execution';
export default function () {
const tag = exec.vu.tags['scenario'];
console.log(tag); // default
}
ステージにタグを付ける
k6-jslib-utilsプロジェクトのいくつかのヘルパー関数のおかげで、エグゼキュータがステージオプションをサポートしている場合、現在進行中のステージに関するタグを追加できます。他のタグと同様に、このタグはイテレーション中に収集されたすべてのサンプルに追加されます。
実行された操作にタグを付ける方法の1つは、tagWithCurrentStageIndex関数を呼び出して、それらを実行したステージを識別するためのステージタグを設定することです。
import http from 'k6/http';
import exec from 'k6/execution';
import { tagWithCurrentStageIndex } from 'https://jslib.k6.io/k6-utils/1.3.0/index.js';
export const options = {
stages: [
{ target: 5, duration: '5s' },
{ target: 10, duration: '10s' },
],
};
export default function () {
tagWithCurrentStageIndex();
// all the requests will have a `stage` tag
// with its value equal to the index of the stage
http.get('https://test.k6.io'); // e.g. {stage: "1"}
}
さらに、プロファイリング関数 tagWithCurrentStageProfile を使用すると、現在実行中のステージの計算されたプロファイルを持つタグを追加できます。
import http from 'k6/http';
import exec from 'k6/execution';
import { tagWithCurrentStageProfile } from 'https://jslib.k6.io/k6-utils/1.3.0/index.js';
export const options = {
stages: [{ target: 10, duration: '10s' }],
};
export default function () {
tagWithCurrentStageProfile();
// all the requests are tagged with a `stage` tag
// with the index of the stage as value
http.get('https://test.k6.io'); // {stage_profile: ramp-up}
}
現在のステージに基づいたプロファイル値は、以下のオプションのいずれかとなります:
- ramp-up 現在のステージの目標が前のステージの目標よりも大きい
- steady 現在のステージの目標が前のステージの目標と等しい
- ramp-down 現在のステージの目標が前のステージの目標よりも小さい
結果出力の中でのタグ
{
"type ": "Point ",
"data ": {
"time ": "2017-05-09T14:34:45.239531499+02:00 ",
"value ": 459.865729,
"tags ": {
"group ": "::my group::json ",
"method ": "GET ",
"status ": "200 ",
"url ": "https://httpbin.test.k6.io/get "
}
},
"metric ": "http_req_duration "
}
グループ
追加の整理のために、関数ごとに負荷スクリプトを整理するためにグループを使用できます。BDDスタイルのテストのために、グループを入れ子にすることもできます。
グループで発行されるすべてのメトリクスには、値が “::”(二重コロン)で区切られた、全てのラップするグループ名を含む “group” というタグがあります。ルートグループは名前 ”(空の文字列)を使用します。たとえば、cool requests という単一のグループがある場合、そのグループの実際の値は ::cool requests です。
例えば、グループを使用して、ページの読み込みまたはユーザーアクションごとに複数のリクエストを整理することができます。
import { group } from 'k6';
export default function () {
group('visit product listing page', function () {
// ...
});
group('add several products to the shopping cart', function () {
// ...
});
group('visit login page', function () {
// ...
});
group('authenticate', function () {
// ...
});
group('checkout process', function () {
// ...
});
}
グループは内部で以下のタスクを実行します:
- 各 group() 関数ごとに、k6は group_duration メトリクスを発行し、group関数を実行するのにかかる合計時間を含みます。
- タグ付け可能なリソース(チェック、リクエスト、カスタムメトリクス)がグループ内で実行される場合、k6は現在のグループ名を持つ group タグを設定します。詳細については、タグのセクションを参照してください。
これらのオプション、group_duration メトリクスとグループのタグ付けは、複雑なテスト結果を分析および視覚化するのに役立ちます。k6の結果出力でこれらがどのように機能するかを確認してみてください。
非推奨:リクエストごとに1つのグループを作成する
各リクエストを個別のグループに包むことは、不要な冗長なコードを追加する可能性があります。
import { group, check } from 'k6';
import http from 'k6/http';
const id = 5;
// reconsider this type of code
group('get post', function () {
http.get(`http://example.com/posts/${id}`);
});
group('list posts', function () {
const res = http.get(`http://example.com/posts`);
check(res, {
'is status 200': (r) => r.status === 200,
});
});
前述のスニペットのコードが似ている場合、よりクリーンなコードを記述するための以下の戦略を検討してみてください:
- 動的なURLの場合、URLのグループ化機能を使用します。
- リクエストに意味のある名前を付けるために、tags.name の値を設定します。
- 共通のロジックを再利用したり、コードをより整理したりするために、関数内でロジックをグループ化したり、ローカルのJavaScriptモジュールを作成してテストスクリプトにインポートしたりします。
- 高度なユーザーパターンをモデル化するには、シナリオを確認してみてください。
おわりに
今日は、k6におけるtagとgroupについてご紹介しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント