LDIで開発しているOKです。
前回に続き k6 ついて書きます。
今回はよりサーバの負荷試験を意識して、複数のAPIをそれぞれ別の rps (Request / Seconds)で負荷をかける際のやり方です。
実際に動いているサービスだとAPI毎に負荷って違いますよね。 「API①もAPI②も全部 10rps です」なんて事は無いと思うので、 そういった時の書き方です。
K6 環境構築
前回 の環境に加えて、
mix.js を追加しています。
k6Demo/
- docker-compose.yml
- src/
- get.js
- post.js
- mix.js
- env/
- staging.yml
- production.yml
k6 のスクリプト作成
前回説明していなかった post.js と 今回追加した mix.js を書いていきます。
post.js
まずは post.js ですが、ほぼ前回の get.js と同じように書けます。
違いは body を指定しているのと URLとか名前くらいです。
import http from 'k6/http'; import { check, sleep, group } from 'k6'; // 1. 初期化 // 2. API実行前の処理 export function setup() { console.log(__ENV.ENV) } // 3. API実行 export default function() { group('PostGroup', postAPI); } export function postAPI() { const body = `{ "hoge": "hogehoge" }` const res = http.post(__ENV.HOST + `/k6demo/post`, body, { tags: { name: "PostAPI", }, }); const checkStatus = check(res, { 'status was 200': (r) => r.status === 200, }); if (!checkStatus) { return; } const checkBody = check(res, { 'body was OK': (r) => r.json().result === 'POST', }); if (!checkBody) { return; } sleep(1); }
mix.js
続いて mix.js です。
/** 複数APIのパフォーマンスを測るテスト 書き方は https://k6.io/docs/using-k6/scenarios/ を参照 exec には実施するメソッド名を記載 */ import { group } from 'k6'; import { getAPI } from "./get.js"; import { postAPI } from "./post.js"; export const options = { scenarios: { // Get APIのシナリオ // 例) 5分間 5rps(rate/timeUnit) exec を実行する get_scenario: { executor: 'constant-arrival-rate', duration: '5m', rate: 5, timeUnit: '1s', preAllocatedVUs: 2, maxVUs: 10, exec: 'get' }, // Post APIのシナリオ // 例) 5分間 1.5rps(rate/timeUnit) exec を実行する post_scenario: { executor: 'constant-arrival-rate', duration: '5m', rate: 3, timeUnit: '2s', preAllocatedVUs: 2, maxVUs: 10, exec: 'post' }, }, }; export function setup() { console.log(__ENV.ENV) } export function get() { group('GetGroup', getAPI); } export function post() { group('PostGroup', postAPI); }
今回の肝になるのは 10行目から記載されている options に指定した scenarios になります。
ここに実行する API の設定を書いていきます。
まずは executor に constant-arrival-rate を指定してください。
これは 期間内 (timeUnit) に、指定のリクエスト数 (rate) を反復して繰り返す というような負荷をかけてくれます。
「rate/timeUnit」 で rps を計算できる形です。
その他のパラメータはこんな感じです。 詳細は こちら
| 項目 | 説明 |
|---|---|
| duration | 負荷をかけ続ける期間 |
| preAllocatedVUs | 負荷をかけ始める前に事前に保持しておくVU数(Virtual Users) |
| maxVUs | 許容する最大のVU数(思ったよりパフォーマンスがでない場合にVU数をあげすぎないようにする感じかな) |
| exec | そのシナリオで実行するメソッド名 |
k6 実行
次のコマンドで実行します。
今回は、mix.js に負荷の設定があるので、 --vus や --duration の指定の必要がありません。
docker-compose -f docker-compose.yml run --rm k6 run --out csv=/output/result.csv /src/mix.js
実行すると以下のようにサマリが出力されます。 残念な事にサマリの結果はシナリオ毎に出してくれないです。
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: /src/mix.js
output: InfluxDBv1 (http://influxdb:8086)
scenarios: (100.00%) 2 scenarios, 20 max VUs, 5m30s max duration (incl. graceful stop):
* get_scenario: 5.00 iterations/s for 5m0s (maxVUs: 2-10, exec: get, gracefulStop: 30s)
* post_scenario: 1.50 iterations/s for 5m0s (maxVUs: 2-10, exec: post, gracefulStop: 30s)
INFO[0000] Docker環境 source=console
running (5m00.6s), 00/10 VUs, 1944 complete and 0 interrupted iterations
get_scenario ✓ [======================================] 00/07 VUs 5m0s 5.00 iters/s
post_scenario ✓ [======================================] 00/03 VUs 5m0s 1.50 iters/s
█ setup
█ PostGroup
✓ status was 200
✓ body was OK
█ GetGroup
✓ status was 200
✓ body was OK
checks.........................: 100.00% ✓ 3888 ✗ 0
data_received..................: 271 kB 900 B/s
data_sent......................: 222 kB 737 B/s
dropped_iterations.............: 6 0.019961/s
group_duration.................: avg=1s min=1s med=1s max=1.29s p(90)=1s p(95)=1s
http_req_blocked...............: avg=41.12µs min=2.4µs med=9.18µs max=7.12ms p(90)=15.06µs p(95)=56.23µs
http_req_connecting............: avg=15.64µs min=0s med=0s max=6.12ms p(90)=0s p(95)=0s
http_req_duration..............: avg=2.06ms min=479.29µs med=1.82ms max=52.51ms p(90)=3ms p(95)=3.69ms
{ expected_response:true }...: avg=2.06ms min=479.29µs med=1.82ms max=52.51ms p(90)=3ms p(95)=3.69ms
http_req_failed................: 0.00% ✓ 0 ✗ 1944
http_req_receiving.............: avg=208.93µs min=12.34µs med=128.93µs max=6.68ms p(90)=399.84µs p(95)=553.98µs
http_req_sending...............: avg=130.05µs min=9.41µs med=63.05µs max=3.56ms p(90)=260.15µs p(95)=395.01µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=1.72ms min=425.94µs med=1.52ms max=52.42ms p(90)=2.46ms p(95)=2.98ms
http_reqs......................: 1944 6.467257/s
iteration_duration.............: avg=1s min=121.91µs med=1s max=1.29s p(90)=1s p(95)=1s
iterations.....................: 1944 6.467257/s
vus............................: 10 min=6 max=10
vus_max........................: 10 min=6 max=10
結果の見方(詳細)
個々のAPIの結果について確認したい場合は out で指定した csv 側を確認していきます。
画像を見てわかる通り name の列 で GetなのかPostなのか判別ができます。
これは、ソースのなかで tags として指定したものが出力されています。(post.js だと 21行目)
他にも group など APIの判別方法はいくつかありますが、group だと、実行するメソッドの中で複数のAPIを呼び出すようなケースの場合、それらは同じ名前の group で出力されます。
なので、どういった単位でまとめたいかで調整すると良いかと思います。

あとは、 http_req_duration と name でフィルターすれば、API毎の応答時間なんかを見る事ができます。
あとがき
前回に続き、今回は k6 についてより突っ込んだ使い方の1つを紹介しました。
これ以外にもいろんな方法があるので、お使いのサービスに合わせてより良い負荷の掛け方をチューニングしてもらうと良いと思います。
次回は結果の見方について、より深掘りできたらと思います。
それではまた!!