以前とあるプロジェクトで負荷試験を行ったのでその内容を共有します。
利用した技術は以下です(かなり前にやった話なので記憶を辿りながら記載しています)
- 負荷試験ツール: k6
- API方式: GraphQL
- 認証部分: Firebase SDK (Identity platform)
- インフラ: GCE, CloudRun, CloudSQL, Pub/Sub, GCS
目的
GraphQLのクエリは複数のリソースを一度に取得できることからdepth制限等を設けていないと、 クエリのネストが深くなり、DBへの負荷が大きくなることがあります。 そのため、負荷試験を行い、どの程度の負荷がかかるかを確認することが目的です。
負荷試験ツール
負荷試験ツールはk6を利用しました。 k6はGoで書かれた負荷試験ツールで、シンプルな記述で負荷試験を行うことができます。
インストール
k6はバイナリをダウンロードして利用することができます。
また、Dockerイメージも提供されているので、Dockerを利用することもできます。
https://k6.io/docs/getting-started/installation
負荷試験用マシン
負荷試験用マシンはCloudBuildを利用しました。 GCEで利用している例も多いかと思いますが、CloudBuildを利用することで インスタンスの起動から負荷試験の実行、試験終了までを手軽に自動化することができます。
Seedデータについて
負荷試験にDBに大量データを流し込む必要がある場合はそれだけで時間がかかります。
高スペックで高価な負荷試験用のCloudBuildのインスタンスとは別に、低スペックで低価格なCloudBuildインスタンスを利用してデータの流し込みを行うことでコスト節約しました。
認証
負荷試験を行うにあたり、実際の利用ケースと同じくGraphQLサーバに対して認証ヘッダ付きでリクエストの送信が必要でした。 今回の例ではFirebaseのIdentity platformを利用していたのですが、公式資料等を参考に一部コードを調整したため以下に記載します。
JWTの生成
負荷テスト用のJWTを生成するために、以下のようなコードを利用しました。
createCustomToken(uid)
を利用しているのがポイントで、これとIDPのsignInWithCustomToken
のエンドポイントを組み合わせることで実際のJWTが手に入ります。
なお、実際の利用シーンではクライアント側で行うJWTの取得について負荷テストに含める必要がなかったため、 以下の処理はCloudBuildのStepとしてはk6を実行する前の別Stepで行っています。 (複数ユーザのJWTをひとつのjsonにまとめてk6の実行時に読み込むようにしています)
コードサンプル
SEED作成時にIDPにテナントとユーザを作成するためのコード
JWTの入手コード
参考資料
- https://k6.io/docs/examples/oauth-authentication
- https://tech-blog.optim.co.jp/entry/2021/04/01/103000
負荷試験の実行
負荷試験の実行は以下のようなコマンドで実行します。
シナリオ作成
負荷試験のシナリオ作成と簡易的な動作確認はローカルマシンで行いました。 シナリオ開発の序盤では以下のようなコマンドで直接実行していました。(後半ではDocker化して実行していました)