WEARアプリリニューアルにおける負荷試験事例(計画編)

WEARアプリリニューアルにおける負荷試験事例(計画編)

はじめに

こんにちは! WEARバックエンド部バックエンドブロックの高久です。普段は弊社サービスであるWEARのバックエンド開発・保守を担当しています。

10周年を迎えたWEARは2024年5月9日に大規模なアプリリニューアルを行いました。アプリリニューアルに伴い負荷試験を行ったので、本記事ではどのように負荷試験を計画したか事例をご紹介します。

記事は計画編と実施編の2部構成で、本記事は前編の計画編となります。後編の実施編は近日、公開予定です。

目次

背景

前述の通りWEARは2024年5月9日に大規模なアプリリニューアルを実施しました。このリニューアルでは、アプリのほぼすべての画面が刷新され、新たにAIを活用したファッションジャンル診断や、ユーザの閲覧履歴をもとにしたレコメンド機能、ARによるメイク試着機能などが追加されました。リリース後には、会員登録時にポイントがもらえるキャンペーンやWeb広告の出稿により、新規ユーザのさらなる増加が見込まれていました。

このような複数の機能追加・改修やユーザ数の増加に伴い懸念されるのが性能問題です。例えば、新たに作成した機能のクエリに性能問題があってアプリの動作が遅くなったり、ユーザ数の増加によってサーバリソースが不足し、最悪の場合にはシステムダウンしたりする可能性もあります。リリース後にこうした性能問題が発生しないよう、事前に負荷試験を行い、性能品質を担保する必要がありました。

計画の重要性

一般的に負荷試験は本番運用に先立って性能問題が発生しないことを事前に保証することを目的としています。そのため理想的な負荷試験は、本番環境と全く同じ条件、すなわち負荷、データ量、シナリオ、環境などを本番と同様に再現し、性能に問題がないことを確認することです。しかし現実的にそれを実現することはほぼ不可能だと考えています。リリース後にどの機能をどれくらいの人数が利用するかを完璧に予測することは難しかったり、全てのリクエストパターンを網羅するには膨大なシナリオ作成が必要で、多大な工数がかかったりするためです。

理想にできるだけ近づけることは重要ですが、未来の予測は困難で、工数を無限にかけるのも現実的ではありません。そのため現状の環境、人的リソース、期間を考慮し、いかに効率的に性能品質を保証できるかを事前に計画しておくことが重要です。理想に達しなかった部分については、リスクとしてどのように対処するかを計画段階で検討することも必要です。

計画の策定

どのように計画したか、以下のポイントに沿ってご紹介していきます。

  • 目的の整理
  • 目標値の設定
  • 試験方針
  • 試験環境・データ
  • 対象範囲
  • 取得情報・確認観点の整理
  • 負荷シナリオ
  • 実施方法
  • リスク

目的の整理

まず負荷試験の目的を整理しました。WEARでは以下の点を負荷試験の目的としました。

  • 性能要件の担保
    • リリース後に予想されるピーク負荷において、目標とするスループットやレイテンシが達成されているかを確認します。
    • 目標に達しない場合は、達成できるように改善します。

他にも負荷試験ではシステムの限界点の測定やボトルネックの特定、サーバスペックや台数の適正化(サイジング)を目的とすることもあります。しかし今回は負荷試験に割ける期間が限られていたため「性能要件の担保」のみに焦点を当てました。

目標値の設定

目標値(≒性能要件)として「スループット」と「レイテンシ」の2つを定めました。

スループット

現行のピーク負荷量の1.5倍を目標としました。

リリース後1年の中で最も負荷がかかると予想されたのは、リリースから3か月後に予定されているキャンペーン期間で、このタイミングで予想されるユーザー数が現行ピーク負荷の1.3倍でした。この値に安全率を考慮して1.5倍としました。

負荷量の増加要因としてはキャンペーンやプロモーションによる一時的な急増と、サービスの成長に伴うユーザー数の継続的な増加が考えられました。これらを踏まえプロダクトオーナーにヒアリングしながら、最も負荷が大きくなるタイミングを決定しました。

レイテンシ

APIの処理時間について、一次目標を500ms以下、二次目標を1秒以下と設定しました。

測定対象としては、本来クライアント側の処理時間も含めたエンドツーエンドで計測するのが理想です。しかしクライアントのレイテンシ計測方法が確立しておらず、計測には多大な工数がかかると判断したため、今回はAPIの処理時間のみを測定対象としました。クライアント側の処理時間に関しては特別な試験は行わず、関係者(開発者、PM、QA、デザイナー)がアプリを使用する中で「遅い」と感じた箇所など体感ベースで改善する方針としました。

秒数の目標値については、元々WEARで設定されていたSLO(サービスレベル目標)を基に定めました。SLOについては以前テックブログで紹介していますので、ご興味があればご覧ください。

基本的には一次目標である500msを目指しました。もし500msを超えてしまった場合は、エンドポイントの重要度(リクエスト数など)や処理内容(重い処理かなど)に応じて、二次目標を基準に測定を続けるか、500ms以下に改善するかを都度判断しました。

試験方針

初めにAPI単体の性能試験を実施し、その後システム全体でリクエストされる想定のAPIに対して一斉に負荷をかけて本番運用を模擬した負荷試験を実施しました。

API単体の性能試験では、単発でAPIを実行しレイテンシが目標値を下回っているかを確認します。もし目標に達していなければチューニングを行います。このAPI単体の性能試験を先に行う理由は、試験の効率化のためです。いきなり負荷試験を実施しても良いのですが、仮に目標未達のAPIがあった場合その都度、負荷試験を実施してチューニングと再測定を繰り返すと調整や工数が増加します。また全てのAPIを負荷シナリオに含めることは工数的に難しい場合が多いため、リクエスト頻度が低いなどの優先度が低いAPIについては、負荷試験を行わずAPI単体の性能試験のみで最低限の品質を担保します。

試験種別 確認観点 担保できる品質
API単体の性能試験 単発でリクエストを送った際に、レイテンシが目標を満たしているか確認 ・遅い処理がないこと(例: N+1、無駄なループ、非効率なクエリ・実行計画、外部システム)
負荷試験 複数のAPIに対して複合的な負荷をかけた際に、レイテンシやスループットが目標を満たしているか確認 ・サーバリソースが十分であること(例: CPU、メモリ、ディスク)
・DBロックが頻発しないこと
・コネクション数(例: DBのコネクションプールなど)が十分であること
など

試験環境・データ

試験環境は本番運用中の本番環境、データも本番環境のものを使用しました。

今回APIを提供するサーバはリニューアルせず、既存のサーバにAPIを追加する形でした。そのため本番環境で負荷試験を行うと、現行のWEARユーザに影響を与えるリスクがありました。

WEARにはステージング環境と本番環境の2種類があります。ユーザへの影響を考慮すると、できればステージング環境で試験を実施したかったのですが、以下の理由により本番環境での実施を決定しました。

  • DBスペックの違い
    ステージング環境のDBスペックは本番環境よりも低い状態でした。このため、ステージング環境で負荷試験を行った場合、レイテンシが悪化し性能問題が発生する可能性が高くなります。仮に性能問題が発生した場合、その原因がシステム本体の問題なのか、環境要因によるものなのかを切り分ける必要が生じ、追加の工数と時間がかかることが予想されました。

  • データの量と質の違い
    ステージング環境では、時間的制約から本番環境と同等のデータ量や質を揃えることが難しい状況でした。特にSQLの実行計画や処理時間はデータの量と質に大きく依存しており、その違いはパフォーマンス測定の正確性に直接影響を与えます。例えばデータボリュームの少ない環境で負荷試験を行うと、データ取得にかかる時間が早くなって本番環境よりもいい結果になってしまうこともあるなど、本番稼働時に予期しない遅延や問題のリスクがあります。

試験の正確性とリスクを天秤にかけ、今回は本番環境で試験を実施することにいたしました。

対象範囲

試験の対象範囲を事前に以下のように決定しました。

観点 試験対象内(例) 試験対象外(例)
インフラ APIサーバ、DB、外部システムの一部、Elasticsearch クライアント、外部システムの一部、Push通知基盤、メール送信基盤
API(単体の性能試験) 新規API、既存API(改修あり)、新規実装したバッチ 既存API・バッチ(改修なし) 
API(負荷試験) 想定リクエスト量がNrps以上のAPI 想定リクエスト量がNrps以下のAPI、シナリオ作成が難しいAPI 

試験範囲を広げれば、その分負荷試験にかかる工数も増加します。今回の負荷試験では限られた時間の中で実施する必要があったため、リニューアルによって懸念がある箇所や負荷量増加が予測される部分を優先的に試験対象として設定しました。

取得情報・確認観点の整理

負荷試験中の問題調査や未然の問題検知を目的として、事前にSREチームと共に取得するメトリクスを整理しました。要件であるスループットやレイテンシに加え、サーバリソース(CPU、メモリなど)、エラー、DBロック状況といった、特に負荷がかかった際に問題が発生しやすいポイントを中心に取得しました。

一部のメトリクスには達成基準を設け、負荷試験中にその基準を満たしているかを確認しました。

例:

観点 取得方法 達成基準
CPU使用率 datadog 70%以下であること
メモリ datadog 現行と同等程度であること

試験実施時には、Datadog上にすべてのメトリクスをひとまとめに表示できるダッシュボードを作成し、リアルタイムで監視と結果取得をしました。

負荷シナリオ

リリースから3か月後のピーク時に予想されるAPIとその負荷量について検討しました。計画段階では、以下のようにAPIと負荷量の一覧を整理しました。また、今回は運用中の本番環境を利用するため、算出したピーク負荷量をそのままかけてしまうと既存負荷分が余分にかかってしまう状況でした。そのため既存負荷分を差し引いた負荷をかけられるように既存負荷量も時間帯ごとに整理しておきました。

例:

API 想定ピーク負荷量(rps) 7~19時の現在負荷量 21時の現在負荷量 4時の現在負荷量
コーデ詳細取得API 100 60 80 30
ユーザ情報取得API 50 20 40 10
コーデ投稿API 10 5 6 3

今回、負荷量予測が難しかったです。これまでの機能単体リリースであれば現行システムの負荷量を基におおよその予測はできました。しかし今回は画面や機能の大幅に変更によって、リニューアル前後で負荷量の傾向は大きく変わる可能性があり、予測は難しい状況でした。

以下に負荷量予測の算出方法を簡単に説明します。

  1. 現行アクセスログの分析: 現行システムの直近1年間のピーク秒を特定し、そのピーク秒を含む5秒間のAPIごとのアクセス数を取得します。このデータを基にリニューアル後の負荷量を予測します。
  2. リニューアル後の予測: 新しい画面や機能のアクセス傾向を予測します。例えば「新A画面は旧B画面に似ているので、B画面のリクエスト数と同程度だろう」や「この機能は初回の起動以外ほとんど使われないだろうから、初回起動のリクエスト数と同等だろう」といった形で予測を立てます。予測の精度を高めるには時間がかかるため、重要な画面に関しては詳細に、その他の画面は感覚で決めました。
  3. API一覧の整理: 各画面や機能ごとに呼び出されるAPIの一覧を整理します。HTTP通信トレースツール(Charles)を使用し、画面ごとに呼び出されるAPIを抽出しました。
  4. 負荷量の算出: 1、2、3の情報を基に、各APIの負荷量を算出します。
  5. 試験対象の絞り込み: 効率化のためにリクエスト量が0.7rps以下のAPIは試験対象から外しました。また外したAPI分の負荷量を、試験対象APIの負荷量に追加しました。

この方法で負荷シナリオを整理しました。負荷掛けツールでの実行ファイルへの落とし込み方法については、実施編で説明する予定です。

実施方法

本番環境のサーバに対して、k6というツールを使用して負荷をかけて測定しました。詳細については、実施編でお伝えする予定です。

リスク

事前に負荷試験を実施する際とリリース後に起こり得るリスクを洗い出し、それぞれに対する対処案を整理しました。以下のようなリスクが考えられました。

リリースしてみたらユーザ数が予想を超えてしまい性能問題が発生する

  • 対策
    • 想定ピーク負荷量に安全率を持たせ、予想を少し超えても問題がないことを確認しておく。
    • ユーザ数の増加が見込まれるキャンペーンやテレビでのサービス紹介などのイベント時には、監視体制を整え、問題発生時に迅速に対応できるようにする。
    • リリース後は負荷量を定期的にモニタリングし、傾向や問題の有無をチェックして未然に問題を防ぐ。
    • システムの限界時にボトルネックとなりそうな箇所を事前に推測し対策案を検討しておくことで、万が一システム限界が訪れた場合、素早く対策できるようにする。

試験対象外とした箇所に性能問題が発生する

  • 対策
    • 影響が大きい利用頻度の高い箇所や、新規に開発または改修した性能問題の発生が懸念される箇所は試験対象に含めて、問題発生の影響や可能性を下げる。
    • リリース後定期的にモニタリングを行い、問題を発見できるようにする。

本番環境での試験時に性能問題が発生しユーザ影響が出る

  • 対策
    • 負荷量を段階的に増やし(10%→30%→50%→100%)、都度結果を確認し負荷を増やしても問題がないかを確認することで、問題発生の可能性を下げる。
    • ユーザ数が少ない夜間帯に試験を実施し、万が一問題が発生した場合の影響を最小限に抑える。
    • 試験中はエラーを常に監視し、ユーザ影響が出た場合にすぐに負荷を中止できるように準備しておく。
    • 最悪の場合にシステム停止の可能性もあるため、事前に関係者と情報連携の方法を共有し、問題発生時にスムーズに対応できるようにする。

まとめ

WEARアプリのリニューアルにおける負荷試験の計画についてご紹介しました。負荷試験の方法は、サービスの特性や環境、利用できる期間や人的リソースによって大きく変わるため、プロダクトに最適な試験を実施するための計画が重要です。WEARでの事例が参考になれば幸いです。なお、本計画に基づいて実施した結果は、後編の「実施編」で紹介しますので公開をお待ちください。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com

カテゴリー