💬
負荷テストツールのk6を試してみた
はじめに
一定期間、緩やかなアクセスを繰り返した場合に、サーバの負荷がどのように変化するのか知りたくなり、調べたところk6がよさそうだったので、試してみました。
環境
k6 v0.39.0
k6による負荷テスト
インストール
今回は、Homebrewでインストールします。
$ brew install k6
$ k6 version
k6 v0.39.0 ((devel), go1.18.3, darwin/amd64)
これ以外にも、Linux,Windows,Dockerなど、複数の方法が提供されています。
負荷テストの実行
公式サイトの Getting Started の手順にそって、負荷テストを実行してみます。
- テストの実行
script.js
import http from 'k6/http';
import { sleep } from 'k6';
export default function () {
http.get('https://test.k6.io');
sleep(1);
}
オプションを指定しない場合は、1並列で、script.jsが1回だけ実行されます。
$ k6 run script.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: script.js
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.6s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs 00m01.6s/10m0s 1/1 iters, 1 per VU
data_received..................: 17 kB 10 kB/s
data_sent......................: 438 B 267 B/s
http_req_blocked...............: avg=444.31ms min=444.31ms med=444.31ms max=444.31ms p(90)=444.31ms p(95)=444.31ms
http_req_connecting............: avg=198.15ms min=198.15ms med=198.15ms max=198.15ms p(90)=198.15ms p(95)=198.15ms
http_req_duration..............: avg=176.7ms min=176.7ms med=176.7ms max=176.7ms p(90)=176.7ms p(95)=176.7ms
{ expected_response:true }...: avg=176.7ms min=176.7ms med=176.7ms max=176.7ms p(90)=176.7ms p(95)=176.7ms
http_req_failed................: 0.00% ✓ 0 ✗ 1
http_req_receiving.............: avg=231µs min=231µs med=231µs max=231µs p(90)=231µs p(95)=231µs
http_req_sending...............: avg=6.12ms min=6.12ms med=6.12ms max=6.12ms p(90)=6.12ms p(95)=6.12ms
http_req_tls_handshaking.......: avg=233.21ms min=233.21ms med=233.21ms max=233.21ms p(90)=233.21ms p(95)=233.21ms
http_req_waiting...............: avg=170.35ms min=170.35ms med=170.35ms max=170.35ms p(90)=170.35ms p(95)=170.35ms
http_reqs......................: 1 0.610261/s
iteration_duration.............: avg=1.62s min=1.62s med=1.62s max=1.62s p(90)=1.62s p(95)=1.62s
iterations.....................: 1 0.610261/s
vus............................: 1 min=1 max=1
vus_max........................: 1 min=1 max=1
- オプションの指定
並列数(--vus 3)と期間(--duration 30s)を指定して、テストを実行してみます。
$ k6 run --vus 3 --duration 30s script.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: script.js
output: -
scenarios: (100.00%) 1 scenario, 3 max VUs, 1m0s max duration (incl. graceful stop):
* default: 3 looping VUs for 30s (gracefulStop: 30s)
running (0m31.1s), 0/3 VUs, 74 complete and 0 interrupted iterations
default ✓ [======================================] 3 VUs 30s
data_received..................: 855 kB 28 kB/s
data_sent......................: 8.3 kB 266 B/s
http_req_blocked...............: avg=20.94ms min=4µs med=7µs max=518.48ms p(90)=11µs p(95)=41.59µs
http_req_connecting............: avg=10.05ms min=0s med=0s max=248.01ms p(90)=0s p(95)=0s
http_req_duration..............: avg=222.86ms min=160.6ms med=226.32ms max=433.55ms p(90)=229.38ms p(95)=230.02ms
{ expected_response:true }...: avg=222.86ms min=160.6ms med=226.32ms max=433.55ms p(90)=229.38ms p(95)=230.02ms
http_req_failed................: 0.00% ✓ 0 ✗ 74
http_req_receiving.............: avg=8.72ms min=61µs med=119µs max=224.24ms p(90)=248.8µs p(95)=438.19µs
http_req_sending...............: avg=44.68µs min=16µs med=37.5µs max=268µs p(90)=71.2µs p(95)=97.79µs
http_req_tls_handshaking.......: avg=9.03ms min=0s med=0s max=224.73ms p(90)=0s p(95)=0s
http_req_waiting...............: avg=214.09ms min=160.44ms med=225.81ms max=230.17ms p(90)=228.7ms p(95)=229.36ms
http_reqs......................: 74 2.378671/s
iteration_duration.............: avg=1.24s min=1.16s med=1.22s max=1.71s p(90)=1.23s p(95)=1.43s
iterations.....................: 74 2.378671/s
vus............................: 1 min=1 max=3
vus_max........................: 3 min=3 max=3
オプションは、スクリプト内でも指定することもできます。
script.js
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
vus: 3,
duration: '30s',
};
export default function () {
http.get('http://test.k6.io');
sleep(1);
}
CLIのオプションを指定せずに実行しても、並列数(--vus 3)、期間(--duration 30s)と指定した場合と同様にテストが実行されます。
$ k6 run script.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: script.js
output: -
scenarios: (100.00%) 1 scenario, 3 max VUs, 1m0s max duration (incl. graceful stop):
* default: 3 looping VUs for 30s (gracefulStop: 30s)
running (0m31.1s), 0/3 VUs, 75 complete and 0 interrupted iterations
default ✓ [======================================] 3 VUs 30s
data_received..................: 866 kB 28 kB/s
data_sent......................: 8.4 kB 270 B/s
http_req_blocked...............: avg=21.01ms min=2µs med=6µs max=525.87ms p(90)=13µs p(95)=42.79µs
http_req_connecting............: avg=9.79ms min=0s med=0s max=244.83ms p(90)=0s p(95)=0s
http_req_duration..............: avg=219.93ms min=163.32ms med=227.6ms max=241.79ms p(90)=228.79ms p(95)=229.8ms
{ expected_response:true }...: avg=219.93ms min=163.32ms med=227.6ms max=241.79ms p(90)=228.79ms p(95)=229.8ms
http_req_failed................: 0.00% ✓ 0 ✗ 75
http_req_receiving.............: avg=124.81µs min=37µs med=104µs max=442µs p(90)=191.2µs p(95)=247.59µs
http_req_sending...............: avg=34.85µs min=8µs med=31µs max=99µs p(90)=61µs p(95)=73.89µs
http_req_tls_handshaking.......: avg=10.84ms min=0s med=0s max=273.32ms p(90)=0s p(95)=0s
http_req_waiting...............: avg=219.77ms min=163.18ms med=227.4ms max=241.62ms p(90)=228.66ms p(95)=229.7ms
http_reqs......................: 75 2.41479/s
iteration_duration.............: avg=1.24s min=1.16s med=1.22s max=1.76s p(90)=1.23s p(95)=1.23s
iterations.....................: 75 2.41479/s
vus............................: 3 min=3 max=3
vus_max........................: 3 min=3 max=3
- レスポンスの検証
リクエストに対するレスポンスの検証も行えます。
レスポンスのステータスコードが200であることを検証する場合は、スクリプトを以下のように記述します。
script.js
import { check } from 'k6';
import http from 'k6/http';
export default function () {
const res = http.get('http://test.k6.io/');
check(res, {
'is status 200': (r) => r.status === 200,
});
}
$ k6 run script.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: script.js
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.7s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs 00m01.7s/10m0s 1/1 iters, 1 per VU
✓ is status 200
checks.........................: 100.00% ✓ 1 ✗ 0
data_received..................: 17 kB 9.9 kB/s
data_sent......................: 438 B 259 B/s
http_req_blocked...............: avg=495.37ms min=495.37ms med=495.37ms max=495.37ms p(90)=495.37ms p(95)=495.37ms
http_req_connecting............: avg=277.44ms min=277.44ms med=277.44ms max=277.44ms p(90)=277.44ms p(95)=277.44ms
http_req_duration..............: avg=193.77ms min=193.77ms med=193.77ms max=193.77ms p(90)=193.77ms p(95)=193.77ms
{ expected_response:true }...: avg=193.77ms min=193.77ms med=193.77ms max=193.77ms p(90)=193.77ms p(95)=193.77ms
http_req_failed................: 0.00% ✓ 0 ✗ 1
http_req_receiving.............: avg=234µs min=234µs med=234µs max=234µs p(90)=234µs p(95)=234µs
http_req_sending...............: avg=75µs min=75µs med=75µs max=75µs p(90)=75µs p(95)=75µs
http_req_tls_handshaking.......: avg=216.13ms min=216.13ms med=216.13ms max=216.13ms p(90)=216.13ms p(95)=216.13ms
http_req_waiting...............: avg=193.46ms min=193.46ms med=193.46ms max=193.46ms p(90)=193.46ms p(95)=193.46ms
http_reqs......................: 1 0.590737/s
iteration_duration.............: avg=1.69s min=1.69s med=1.69s max=1.69s p(90)=1.69s p(95)=1.69s
iterations.....................: 1 0.590737/s
vus............................: 1 min=1 max=1
vus_max........................: 1 min=1 max=1
- 並列数の増減
オプションの stages を利用すると、テスト中の並列数も変更できます。
最初の30秒で並列数を5まで増加させ、次の30秒で並列数を3に減少させ、最後の30秒で並列数を0にします。
script.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 5 },
{ duration: '30s', target: 3 },
{ duration: '30s', target: 0 },
],
};
export default function () {
const res = http.get('https://httpbin.test.k6.io/');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
}
$ k6 run script.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: script.js
output: -
scenarios: (100.00%) 1 scenario, 5 max VUs, 2m30s max duration (incl. graceful stop):
* default: Up to 5 looping VUs for 2m0s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
running (2m00.9s), 0/5 VUs, 285 complete and 0 interrupted iterations
default ✓ [======================================] 0/5 VUs 2m0s
✓ status was 200
checks.........................: 100.00% ✓ 285 ✗ 0
data_received..................: 2.8 MB 23 kB/s
data_sent......................: 32 kB 264 B/s
http_req_blocked...............: avg=7.38ms min=3µs med=7µs max=446.05ms p(90)=11µs p(95)=13µs
http_req_connecting............: avg=3.53ms min=0s med=0s max=233.87ms p(90)=0s p(95)=0s
http_req_duration..............: avg=215.56ms min=161.99ms med=227ms max=488.96ms p(90)=229.88ms p(95)=232.9ms
{ expected_response:true }...: avg=215.56ms min=161.99ms med=227ms max=488.96ms p(90)=229.88ms p(95)=232.9ms
http_req_failed................: 0.00% ✓ 0 ✗ 285
http_req_receiving.............: avg=130.98µs min=46µs med=100µs max=2.92ms p(90)=172.39µs p(95)=219.4µs
http_req_sending...............: avg=37.09µs min=14µs med=36µs max=252µs p(90)=52µs p(95)=60µs
http_req_tls_handshaking.......: avg=3.78ms min=0s med=0s max=228.81ms p(90)=0s p(95)=0s
http_req_waiting...............: avg=215.39ms min=161.83ms med=226.86ms max=488.87ms p(90)=229.67ms p(95)=232.8ms
http_reqs......................: 285 2.356448/s
iteration_duration.............: avg=1.22s min=1.16s med=1.22s max=1.64s p(90)=1.23s p(95)=1.24s
iterations.....................: 285 2.356448/s
vus............................: 1 min=1 max=5
vus_max........................: 5 min=5 max=5
CLIでオプションを指定する場合は、以下のようにします。
$ k6 run -s '1m:5' -s '30s:3' -s '30s:0' script.js
- Basic認証が設定されている場合
$ curl -i https://httpbin.test.k6.io/basic-auth/user/passwd
HTTP/1.1 401 UNAUTHORIZED
Date: Mon, 18 Jul 2022 06:43:20 GMT
Content-Length: 0
Connection: keep-alive
WWW-Authenticate: Basic realm="Fake Realm"
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
$ curl -i --user 'user:passwd' https://httpbin.test.k6.io/basic-auth/user/passwd
HTTP/1.1 200 OK
Date: Mon, 18 Jul 2022 06:43:59 GMT
Content-Type: application/json
Content-Length: 47
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
{
"authenticated": true,
"user": "user"
}
basic-auth.js
import encoding from 'k6/encoding';
import http from 'k6/http';
import { check } from 'k6';
const username = 'user';
const password = 'passwd';
export default function () {
const credentials = `${username}:${password}`;
const url = `https://${credentials}@httpbin.test.k6.io/basic-auth/${username}/${password}`;
let res = http.get(url);
check(res, {
'status is 200': (r) => r.status === 200,
'is authenticated': (r) => r.json().authenticated === true,
'is correct user': (r) => r.json().user === username,
});
}
$ k6 run basic-auth.js
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: basic-auth.js
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 (00m00.6s), 0/1 VUs, 1 complete and 0 interrupted iterations
default ✓ [======================================] 1 VUs 00m00.6s/10m0s 1/1 iters, 1 per VU
✓ status is 200
✓ is authenticated
✓ is correct user
checks.........................: 100.00% ✓ 3 ✗ 0
data_received..................: 5.7 kB 9.7 kB/s
data_sent......................: 515 B 870 B/s
http_req_blocked...............: avg=399ms min=399ms med=399ms max=399ms p(90)=399ms p(95)=399ms
http_req_connecting............: avg=207.9ms min=207.9ms med=207.9ms max=207.9ms p(90)=207.9ms p(95)=207.9ms
http_req_duration..............: avg=171.46ms min=171.46ms med=171.46ms max=171.46ms p(90)=171.46ms p(95)=171.46ms
{ expected_response:true }...: avg=171.46ms min=171.46ms med=171.46ms max=171.46ms p(90)=171.46ms p(95)=171.46ms
http_req_failed................: 0.00% ✓ 0 ✗ 1
http_req_receiving.............: avg=183µs min=183µs med=183µs max=183µs p(90)=183µs p(95)=183µs
http_req_sending...............: avg=5.39ms min=5.39ms med=5.39ms max=5.39ms p(90)=5.39ms p(95)=5.39ms
http_req_tls_handshaking.......: avg=188.94ms min=188.94ms med=188.94ms max=188.94ms p(90)=188.94ms p(95)=188.94ms
http_req_waiting...............: avg=165.89ms min=165.89ms med=165.89ms max=165.89ms p(90)=165.89ms p(95)=165.89ms
http_reqs......................: 1 1.689889/s
iteration_duration.............: avg=576.97ms min=576.97ms med=576.97ms max=576.97ms p(90)=576.97ms p(95)=576.97ms
iterations.....................: 1 1.689889/s
まとめ
負荷テストツールのk6について、インストールからテストの実行までを試してみました。
また、テスト中の並列数の増減や、認証が設定されたサイトもテストが行えることが確認できました。
CLIツールが提供されているためテストの実行が容易で、また、テスト自体はJavaScriptで記述できるので、とても使いやすいという印象を持ちました。
Discussion