Upgrade to Pro — share decks privately, control downloads, hide ads and more …

k6による負荷試験 入門から実践まで

k6による負荷試験 入門から実践まで

https://techfeed.io/events/techfeed-experts-night-20
TechFeed Experts Night#20 〜 Webパフォーマンス・チューニング最前線 : 前編(概要、モニタリング、負荷テスト編)

FUJIWARA Shunichiro

June 07, 2023
Tweet

More Decks by FUJIWARA Shunichiro

Other Decks in Technology

Transcript

  1. @fujiwara 面白法人カヤック SREチーム ISUCON 1,2,5,11 優勝4回 ISUCON 3,8,12,13 運営(出題)4回 github.com/kayac/ecspresso

    Amazon ECS デプロイツール github.com/fujiwara/lambroll AWS Lambda デプロイツール
  2. シナリオの作り方 まず単一URL連打から import http from 'k6/http' import { check }

    from 'k6' export default function () { let res = http.get('https://example.com/') check(res, { 'success': (r) => r.status === 200 }) } いきなり複雑なものは書かない
  3. k6で実行 最初は「並列度(vus=virtual users)」= 1 から $ k6 run --vus 1

    --duration 300s simple.js checks.............: 99.98% ✓ 52644 ✗ 6 http_req_duration..: avg=285.56ms min=32.93ms med=144.61ms max=30.05s p(90)=521.34ms p(95)=788.36ms http_reqs.. ......: 52650 172.404676/s (いっぱい出力があるけど)とりあえずこの3個を見る checks: コード内の check() の成功・失敗数 レイテンシ: http_req_duration スループット: http_reqs
  4. 結果を評価する 1. k6の出力とサーバー側のメトリクスに齟齬がないか →メトリクスの取得がおかしい可能性が高いので見直す 2. checksは想定通りか →エラーが目標/想定より多い場合は性能を評価する意味がない 原因を調査する 3. レイテンシは目標に達しているか

    →これ以上並列度を増やすのはたいてい無意味 ボトルネックの調査をする 4. スループットは目標に達しているか or →並列度を2倍にして変化を見る 無闇に変数を変えて試さない
  5. シナリオを増やしていく 1. 参照系のリクエスト/画面遷移を足す 2. ログイン/更新系のリクエストを足す (コードの具体例はISUCON本 4章に) 本番のアクセスパターンと負荷を網羅しようと思うのはやめよう(大変) 1. 一連のシナリオごとに実行する

    例: トップ→ログイン→マイページ→お知らせを見る これだけでも特定の箇所で大きな問題がある場合には改善点が分かる 2. 複数のシナリオを混ぜて実行する 複数シナリオを実際に想定される程度の割合で混ぜる
  6. クライアント側で起きる問題の頻出例 ネットワーク帯域が上限を打っている 1Gbpsの回線で1MBのレスポンスを取得→(たったの)125req/sec(=125MB/sec) HTTP Keep-Aliveが無効になっている 3 way handshake のオーバーヘッドが大きい 無駄にファイルディスクリプタ(ソケット)を使う

    Goで自作した場合にやりがち: http.Response.Body を全て読み切らない →次のリクエスト時は新規のTCP接続になる ファイルディスクリプタを使い果たしている ulimit -n (max open files)がデフォルトの1024 ローカルポート(エフェメラルポート)が枯渇している 大量/高速にリクエストを送受信すると使い果たす ISUCON本 9章をどうぞ
  7. k6 応用編 k6は基本的に、シングルプロセス(1台)で動作するツール クラスタリングの仕組みは公式には提供されていない Unless you need more than 100,000-300,000

    requests per second (6-12M requests per minute), a single instance of k6 is likely sufficient for your needs. https://k6.io/docs/testing-guides/running-large-tests/ 公式 「10〜30万req/secぐらいは1インスタンスでいけるで」(チューニング頑張れば) 分散実行をk8sでやる方法も紹介はされているが… https://k6.io/blog/running-distributed-tests-on-k8s/
  8. AWS Step Functions Distributed Mapで k6を分散実行してみた k6を気軽に分散実行したいので試してみた Step Functions(SFn): AWS上でworkflowを定義/実行で

    きるサービス Distributed Map: 大規模(1000並列以上)に並列実行して 結果を集約できる k6をAWS Lambdaで実行できるようにする →SFn Distributed Mapで並列実行!! 1台で大量の負荷を発生させるチューニングが不要に
  9. k6から必要な結果だけJSON出力 シナリオの.jsに handleSummary() を定義すると https://k6.io/docs/results-output/end-of-test/custom-summary/ export function handleSummary(data) { return

    { '/tmp/summary.json': JSON.stringify({ 'checks': data.metrics.checks.values, 'http_reqs': data.metrics.http_reqs.values, }) } } 結果がファイルに出力される {"checks":{"rate":1,"passes":82,"fails":0}, "http_reqs":{"count":82,"rate":27.087064577167027}}
  10. k6をAWS Lambdaで実行 k6が配布しているLinuxバイナリはstatic link Zipに含めてしまえばAWS Lambdaのカスタムランタイム(provided.al2)で実行できる bootstrap > https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtimes- walkthrough.html

    function handler () { cd $LAMBDA_TASK_ROOT # k6 でシナリオを実行する # $1: 関数の引数としてvus を取る ./k6 run --quiet --vus "$1" --duration 30s simple.js # handleSummary で出力した結果をLambda のレスポンスにする cat /tmp/summary.json }
  11. SFn Distributed MapでLambdaを並列実行 SFnへの入力例: 3並列でそれぞれvus=1で実行する ["1", "1", "1"] // この値はvus

    として使われる 配列の値が各Lambda関数への引数になる ./k6 run --vus "$1" --duration 30s simple.js
  12. 分散実行の結果はS3に保存される "Output" : Lambdaが返した結果のJSON文字列 [ { "Input": "\"1\"", "Output": "{\"checks\":{\"rate\":1,\"passes\":82,\"fails\":0},

    \"http_reqs\":{\"count\":82,\"rate\":27.087064577167027}}", "StartDate": "2023-06-06T16:07:24.203Z", "StopDate": "2023-06-06T16:07:41.272Z" // ... }, // ... // 並列分実行した結果が並ぶ ] あとはこれを集計すればよさそう!?