こんにちは。TeamSprit EXのQAエンジニアの河西です。
この記事は、APIテストの取り組みに関する記事の3本目です(全3本)。
- JMeterによるAPIテストの実装について
- JenkinsによるAPIテストの定期実行について
- JMeterを使ったSalesforceアプリへの負荷テストの実施について ◀︎ 今回はこちら
前回までは、APIテストの実装と定期実行の取り組みについてご紹介しました。 今回は、APIテストの実装で習得した知識を活用してSalesforceアプリへの負荷テストを実施した際の、取り組みについて書いていきます。
なぜ負荷テストを実施するのか?
機能テストと、性能を測る性能テストは、全く異なる観点のソフトウェアテストで、どちらも製品を提供するにあたって重要なテストです。
- 機能テスト
仕様書や設計書に基づいた正しい動きをしているかどうか。 - 性能テスト
ユーザーが快適に利用できるかどうか。
実際の利用想定に基づいて、システムのデータ処理や応答速度のボトルネックとなる箇所を検出することを目指す。
性能テストには、通常の状態での処理速度や同時処理数を検証するものに加えて、システムが高負荷の状態にあるときの性能を検証するテストがあります。 これを負荷テストと呼び、その目的に応じていくつかのテストアプローチがあります。
TeamSprit EX は大企業向けのサービスです。
大企業、つまり多くのユーザーにご利用頂ける製品になっているか、検証する必要がありました。
まずは、私たちが想定している最大ユーザー数でご利用頂ける状態か検証するために、ロードテストを実施することにしました。
そこで問題がなかった場合に、想定以上の負荷をかけるストレステストも実施することにしました。
どうやって実施するのか?
まずはテスト計画を立てました。計画を立てる上で、下記の3点を関係者にヒアリングし決定しました。
テストの目的
TeamSprit EX はSalesforce Platform上にアプリケーションを開発しています。 そのため、今回の負荷テストでは「サーバーの性能を測ること」ではなく、「高負荷時のアプリとしての問題点を洗い出すこと」を目的としました。テスト対象
想定しているユーザー数と、どの機能に対して負荷テストを実施するかをヒアリングし、決定しました。 今回は画面操作ではなく、APIリクエストでのテスト実施のため、ターゲットとなるAPIもここで決定しました。 そして、最大でどの程度の負荷をかけるか、RPS(1秒あたりの要求数)を決定しました。スケジュール
いつまでに結果報告が必要かヒアリングし、決定したテスト対象からおおよそのテスト実施期間を決定しました。 初めて負荷テストを実施するということもあり、準備期間は多めに取りました。
ツールの選定については、今回はAPIリクエストによる負荷テストのため、APIテストで使用した JMeter を選びました。
続いて、決定したRPS(1秒あたりの要求数)から負荷を試算し、テストスクリプトの設計をして、JMeterの設定項目「スレッド数」「Ramp-Up期間(s)」「ループ回数」を決定しました。 (参考サイト)
そうして、下記3ケースのテストスクリプトを作成しました。
- 想定しているユーザー数規模(1つのAPIを実行)
RPSは固定のまま、スレッド数を調整して負荷のかけ方を変えた、8パターンを用意しました。 - 想定しているユーザー数の2倍規模(1つのAPIを実行)
RPSは固定のまま、スレッド数を調整して負荷のかけ方を変えた、8パターンを用意しました。 - 5つのAPIを実行
とある画面を表示する際に実行されるAPI5つを実行するテスト。RPS・スレッド数を調整した10パターンを用意しました。
画面を表示する際に実行される5つのAPIを実行するテストケースの方が、より実際の負荷に近いものとなります。 しかし、テスト結果を分析することが少し難しいため、5つの中で1番レスポンスに時間がかかる1つのAPIに重点を置きました。
続いて、テストスクリプトを作成したら、Salesforceアプリへの負荷テスト実施で必要な、Salesforceへのパフォーマンステストの承認申請を行いました。 こちら を確認し、ケースにて申請を行い、承認を得ました。
最後に、テスト環境にテストデータを入れて、準備は完了です。
準備したテストスクリプトを順番に実行しました。
(JMeterのGUIではなく、CLIで実行します。スムーズに実行するために、実行するコマンドを一覧化しておくことをオススメします。
その際、出力するログファイル名は、実行するテストスクリプトのファイル名と同じにしておくと、結果の確認がしやすいです。)
テストの結果
結果が出力されているファイル(result.jtlなど)から、結果を確認します。
(ファイルを、JMeterの「統計レポート」というリスナーで参照すると確認しやすいです。)
結果をExcelでまとめ、有用なデータをグラフ化したものがこちらです。
高い負荷をかけましたがあまり性能劣化は起きておらず、Salesforce Platformの性能の良さを改めて知ることができました。
しかし、一部のリクエストでエラーが発生しました。(赤線の箇所)
発生したエラーは「403 Forbidden」です。
こちらについてSalesforceに確認したところ、 Apexガバナ制限 によるもの、と回答を頂きました。
10個の長時間(5000ms以上)のトランザクションが実行されている間に追加のトランザクションが開始されると、追加のトランザクションは拒否されます
この制限に引っ掛かりました。この制限は組織内だけであり、他組織に影響はありません。同時実行される可能性が高いAPIで、5000ms以上かかるものがあると、この制限が起きる頻度は上がります。
「高負荷時のアプリとしての問題点を洗い出すこと」を目的とした今回の負荷テストでは、上記の結果を得ることができました。
レポートの共有
結果をまとめて、開発メンバーに共有するレポートを作成しました。レポートには、下記の内容を記載しました。
- 結果総評
- テスト結果詳細
- 処理遅延について
- データからの読み取り
- まとめ
- エラー発生について
- データからの読み取り
- エラーの内容
- APIテストとの照合
- まとめ
- 処理遅延について
- 今後の課題について
今回の負荷テストの結果と、定期実行しているAPIテストの結果を踏まえて、今後の課題まで共有することができました。
テスト実行環境について
今回の負荷テストは、PC1台(MacBook Pro2020(Apple M1, 16GB))で実施しました。
計画段階で、PC1台で実施できるのか不安がありましたが、今後の負荷テストの課題を洗い出すためにも、とりあえず今準備できるもので実施してみようと思いました。
負荷テスト実施時は、不要なアプリケーションを全て閉じて、コンソールとアクティビティモニタのみ起動している状態で実施しました。
考えうる課題として、CPU負荷とメモリについてモニタリングしました。
CPU負荷について
テストスクリプトのコマンドを叩いた時、つまりJMeterが立ち上がる時に、一時的にCPU使用率が上がりましたが、それ以外はあまり上がりませんでした。 なるべく余裕のある状態での実施が望ましいですが、今回ほど厳密に全てのアプリケーションを閉じて実施しなくても良い、と思われます。メモリについて
本来、JMeterで負荷テストを実施する際は、先にJVMのチューニングをしておくことが推奨されていますが、今回はあえてチューニングせずに実施してみました。 すると、1500スレッドのテストは問題なく実行できましたが、1920スレッドのテストではメモリ不足によるフリーズにより、テストが止まりました。
そこで、下記のようにJVMのチューニングをしてみました。
すると、1920スレッドのテストも問題なく実行できました。
最大6Gの設定にしましたが、モニタリングしたところ1.5Gまでしか使用されなかったため、まだ余裕があると思われます。
上記の結果から、今回以上の負荷(例えば5000スレッド以上)のテストは、PC1台で実施することは難しそうです。 AWSなどでJMeterサーバーを立てて実施するのが望ましいと考えます。
こうして、テスト実行環境についても課題を洗い出すことができました。
最後に
負荷テストについては、わからないことがとても多く、なかなか計画を立てられず、準備段階でも不安が多くありました。 「わからないことを明確にする」という目的で、とりあえず実施してみると、予想以上に多くの結果を得ることができました。
見つかった課題は Apexガバナ制限 だったため、 負荷テストを実施しないとわからない課題、ではありませんでした。 しかし、普段のテストとは違うアプローチをすることで、潜在的な課題が顕在化し、具体的な影響も見えたことで課題の優先度を判断することができた、と思っています。
APIテスト・負荷テストを任せていただけたことで、とても多くの学びがあり、スキルアップできたと感じています。
新しいアプローチのテストを導入することは大変ではありますが、個人としてもチームとしても、これからもチャレンジし続けたいと思います!