BASEプロダクトチームブログ

ネットショップ作成サービス「BASE ( https://thebase.in )」、ショッピングアプリ「BASE ( https://thebase.in/sp )」のプロダクトチームによるブログです。

カートの負荷試験におけるApache JMeterの活用

f:id:ymiyamura:20190122163945j:plain

先週に引き続き、BASEでサーバサイドエンジニアをしている宮村です。

先日、負荷試験の取り組みについて紹介させていただきましたが、今回はその際に使用したApache JMeterの活用について紹介させていただきたいと思います。

JMeterは高機能なツールなので使いこなすと強力ですが、少し複雑な機能のテストを行おうというとき、ややとっつきにくい部分もあるのではないかと思います(私はそうでした)。具体的な使い方をいくつか知っておくだけで、ぐっと便利に使えるようになると思いますので、これから負荷試験を行おうという方に少しでも参考になれば幸いです。

選定理由

負荷試験を行うツールはいくつかありますが、今回は下記の条件が満たせるものを探していました。

  • セッション管理できること
  • ページ遷移を伴うシナリオが作成できること
  • シナリオでレスポンスの値を取得して使えること
  • 攻撃サーバがスケールすること
  • 習熟コストが高すぎないこと

これが満たされていれば、どれでもいいかな〜と思っていたので、以前少し使ったことがあったJMeterでできそうだと見えてきた時点でJMeterで進めることに決めました。

他に見たものを少しだけ紹介します。

Apache Bench:導入及び使用がとても簡単ですが、複雑なシナリオを扱うことができないため、カートの負荷試験には不向きであると判断しました。

Locust:JMeterと機能的には類似しているとのことで良さそうにも思いましたが、私個人にとってPythonでシナリオを書けることがあまりメリットにならないこともあり、選択しませんでした。

シナリオ作成

下記の手順で、シナリオを準備していきます。

  1. テストケースの作成
  2. 作業PCへのJMeterの導入
  3. 記録コントローラでテストシナリオのベースを作成
  4. 実現したいテストシナリオへ改修

1. テストケースの作成

どのような高負荷状態を作りたいかを決めます。〇〇のページに、単位時間あたり〇〇のアクセスを、〇〇の時間発生させる、というようなものになるかなと思います。 これはツールによらない工程ですが、これがなければシナリオは作れません。今回は、過去の高負荷状態を再現できるようにケースを作成しました。

例)商品Aを1個、クレジットカードで購入するユーザが1分間に100人のペースで5分間来る、等(※数字はイメージです。)

2. 作業PCへのJMeterの導入

公式ページに従い、インストールを行います。

必要に応じてJavaのインストールを併せて行います。

(この工程の情報はWeb上にたくさんありますので、詳細は割愛させていただきます)

3. 記録コントローラでテストシナリオのベースを作成

シナリオ作成には「記録コントローラ」を使用しました。

JMeterをプロキシとして動作させ、ブラウザのプロキシ設定をJMeterに向けることで、ブラウザでの操作をJMeterで記録する機能です。

これを使えば記録したシナリオをそのまま使用できるはずでしたが、いくつかのパラメータが欠けていたので補ったり、不要なシナリオを削除したりといった作業が必要でした。

ただ、この修正の工程が必要であったとしても、記録コントローラを使うメリットは大きいと感じましたのでおすすめです。

4. テストシナリオの改修

1で決めたテストケースを実現できるよう、各種の設定値を書き加えたり変更したりします。

今回は、たとえば商品IDなどのいくつかのパラメータは変数として定義するなど、必要に応じて記録されたシナリオに改修を加えていきました。

ここで、便利だったエレメントを以下に紹介します。

便利だったエレメント8選

  1. ユーザ定義変数
    • 手元の環境でシナリオを作成し、試験環境にで実行するということをしたので、urlなど環境固有の値を簡単に切り替える必要があり使用しました。
  2. HTTP認証マネージャ
    • basic認証をかけた環境で試験をするのに使用しました。
  3. HTTPクッキーマネージャ
    • セッションを利用するので使用しました。
    • 異なるユーザの購入を想定したので、「繰り返しごとにクッキーを破棄する」設定にしました
  4. アサーション
    • 各リクエストで、レスポンスコードは問題ないが、期待するレスポンスが返らない場合にテストを失敗させるため使用しました。
    • 具体的には、正しく次の画面に遷移した場合と、エラーで同じ画面にとどまっているにもかかわらずレスポンスコードは正常な場合を区別したい場合に使用しました。
  5. HTMLリンクパーサ
  6. 正規表現抽出
    • 前の画面で生成した値を、後続のリクエストのパラメータとして使う場合に使用しました。
    • はじめは後述のHTMLリンクパーサを使っていたのですが、JMeterサーバを複数台構成にして、リモート実行した際に正常に動作しないことがあったため、正規表現抽出に切り替えました。
  7. 統計レポート
    • シナリオ実行の様子を眺めるのに使いました。
    • JMeterには様々な高機能なリスナがあり便利なのですが、リクエスト数を増やした場合に、リスナの処理が重くなってしまうそうです。それを避けるため、これとシンプルデータライタの2つだけを実際の試験実行時には使用しました。
  8. シンプルデータライタ
    • シナリオ失敗の具体的な状況を調査するため、結果はすべてCSVファイルに書き出しました。
    • リクエスト失敗の原因調査等、必要に応じてExcelで調査しました。

f:id:ymiyamura:20190128134101p:plain
完成したシナリオの例

実行

シナリオ実行

AWS上のWindowsサーバ1台にJMeterを設置し、少ないリクエスト数から徐々に負荷をかけていきました。

最初は、シナリオや設定値の妥当性の確認も兼ねて、1リクエストから実行していきます。

リクエスト数を増やす過程で、JMeterサーバがボトルネックかな?というタイミングでリモート(Linuxサーバ2台)で実行するように変更しました。 socket write error, failed to respond, closed connection というエラーが、シンプルデータライタで取得したログに出力されたタイミングがそれです。

結果の記録

どういうシナリオを流したか、結果はどうだったかをスプレッドシートに都度記録しました。「実験ノート」をとる要領で、下記のような内容を都度記録しておきました。これが後に結果レポートになっていきます。

  • リクエストの種類
  • 成功数、失敗数
  • シナリオ完了までの時間
    • 成功はしているが遅延している、を検知
  • 実行時刻
    • 各種ログを後から調査するため

まとめ

  • フォームの入力やセッションを利用し、複数画面の遷移を伴う機能であるカート機能の負荷試験を、JMeterを使うことで実施できました。
  • ツールの選定には、試験でどういった機能が必要かをまず明確にするのが重要でした。
  • シナリオが資産として残っているので、今後も改善しながら負荷対策に役立てていく予定です。

最後に

本番相当の環境でのパフォーマンス改善に興味のある方、これからもさらなる改善を行っていくことになると思いますので、ぜひご連絡ください!

herp.careers