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つを紹介しました。
これ以外にもいろんな方法があるので、お使いのサービスに合わせてより良い負荷の掛け方をチューニングしてもらうと良いと思います。
次回は結果の見方について、より深掘りできたらと思います。
それではまた!!