ウェブアプリの負荷テストについてのメモ

負荷テストってどうやってやったらいいんだろう?
って長年思いつつ、適当にabとかで負荷かけてとりあえずDone、みたいなことでお茶を濁してきたわけだけど、最近のプロジェクトで腰を据えてやる機会があり一定の知見を得たのでメモっておく。

手順と心がけるべきいくつかの事柄について。

手順

  • かける負荷の規模を決める
  • シナリオを作る
  • ツールを準備する
  • 負荷テスト対象のサーバーを準備する
  • 負荷をかける側のマシンを準備する
  • データを準備する
  • 負荷テストを走らせる
  • 計測結果を記録する
かける負荷の規模を決める

並列度とシナリオのループ回数くらいを決めておく。
1000並列で5000ループ、みたいな。

パフォーマンスの目標値があればそれをそのまま使うか、目安にできる。

シナリオを作る

ユーザーの実際の動きを想定した画面遷移のシナリオを作る。
これはURLのリストでよい。(リダイレクトなどは考慮すること)

負荷テストをより意味あるものにするためには、実際のユーザーの動きをより忠実に再現したものであることが望ましい。
サービス開始後ならばログから精度の高いシナリオが作成できる。
サービス開始前でもクローズドベータなどで実際のユーザーにさわってもらう機会があれば、そのログからよいシナリオが作れる。

また思わぬところに潜んでいるボトルネックを洗い出すためにシナリオはすべての処理を網羅するようにする。

ツールを準備する
  • 多数のユーザーが
  • 同時にアクセスして
  • 一連のシナリオ(画面遷移)をたどる

という動作をシミュレートできるツールならばなんでもよい。
これらはアプリの負荷テストには必須。

abは指定できるURLがひとつだけなのでちょっと力不足ということになる。
単一ページのチューニングのお供にはお手軽でよいだろうけど。

このあたりは得意な言語で使い捨てのスクリプトを組んでも良いと思う。
また探せばいいツールがいくつかあるようだ。

ツール選びの基準としては上記の必須項目の他に以下のようなものがあげられる。

  • 動作が軽い
  • 設定が簡単
  • レポーティング機能がすぐれている

動作が軽くないと負荷をかける側がボトルネックになって十分に負荷をかけられない場合がある。
そういう意味でJMeterは重いのでよろしくないと思う。

負荷テストについて考える際にいろいろと参考にした『キャパシティプランニング』ではhttperfとかSiegeをおすすめしている。

テスト対象のサーバーを準備する

本番に近い構成のサーバーを準備する。
そういう意味ではサービスのローンチ直前などは本番環境でのテストがやりやすくていい。

負荷をかける側にもリソースが必要になるので、本番環境の構成の半分とか四分の一とかの構成でテストする場合もある。

ローンチ後の負荷テストに関しては理想的には本番環境と同等のテスト環境があればよいが、そんな恵まれた環境は滅多にないと思うのでいったいどうしたらいいのだろうか。
このあたり答えが出ていない。
環境構築やデプロイの自動化が十分にできていればクラウドを使うという選択もあるのだろうか。

負荷をかける側のマシンを準備する

負荷をかける側のマシンも十分に強くないと、負荷をかける側の限界が先に来てしまって負荷をかけきれないので、こちらもちゃんと準備する。
できれば複数台がよい。

ちょっと前までは負荷テスト用にマシンを複数台確保するというのはなかなか現実的ではなかったけれど、最近はEC2などのクラウドがあるので容易に必要なだけ安価に調達できるようになった。
こういうところはまさにクラウドの使いどころ。

データを準備する

サービス開始当初は問題がなくても、データがたまってきて問題が出てくるケースというのは多い。
なので大量の実データを準備することも必要。

データ投入はSQLで行うのが一番速いが、一方で実際にアプリを運用した場合に比べるとデータの抜けが発生する可能性も高い。
なのでSQLによるバルクインサートなどより時間はかかるが実際にアプリの動作によってデータを作るのが一番確実なデータを準備できると思う。

具体的には負荷テストツールでデータの生成をともなうシナリオを作って走らせる。
一度生成したデータはバックアップしておけば、次回データを準備するのは短時間でできるようになる。

負荷テストを走らせる

いろいろと準備ができたので負荷テストを実行する。
最初は少ない負荷をかけてアプリが正しく動いているかどうかを確認する。

これだけ負荷をかけているのにスゴいパフォーマンスだ!
とか思ったら実はほとんどのページがエラーになっていて処理をきちんと実行していなかったなんてこともあり得るので。

一連のシナリオが正しく動いていることが確認できたら本腰を入れて負荷をかける。

負荷をかける側のリソース状況を見て、そちらがいっぱいいっぱいになってないことを確認する。
負荷をかける側がいっぱいいっぱいになっていたら十分に負荷をかけ切れてない可能性があるので、マシンの追加などを検討する。

計測結果を記録する

実行条件とともにしっかり記録しておく。
この結果がパフォーマンスチューニングやキャパシティプランニングの指標になる。

  • 負荷テストツールのレポート結果
  • 負荷をかけている間のサーバーのモニタリング結果
  • httpdのログ
  • スロークエリログ

クライアントから見たパフォーマンスとサーバー側のリソースの変化の両面から。
モニタリングに関してはMRTG、Munin、ZABBIXなどのツールで負荷がかかっている間のグラフが見られるようにしておくとよい。

httpdのログにはレスポンスタイムを含めるようにしておく。(ApacheならばLogFormatに%Dを加える)
そうすれば後で重いページを探し出すことができる。

スロークエリは0.1秒以上かかったらNGとか条件を厳しめにしておくと問題を効果的にあぶり出せる。

心がけるべきいくつかの事柄

負荷テストは負荷をかける側も痛みを伴う

負荷をかける側のマシンリソースが十分でないと負荷をかけきれないことのほか、ウェブアプリの負荷テストはネットワーク帯域を圧迫する。
ネットワーク帯域は意外と盲点なので注意。

パフォーマンスチューニングと負荷テストは別

テスト駆動開発で実装の帽子とリファクタリングの帽子を交互にかぶり直すように、チューニングの帽子と負荷テストの帽子も交互にかぶり直すようにする。
つまりふたつを一緒くたにして同時にやらないように。

これらを同時にやり始めると、ちょっとパラメータを変更しては負荷テストを繰り返すといったスパイラルに陥ってしまいがち。
このスパイラルはとても楽しいが、かかる時間の割に得られるものはそれほど多くない。

負荷テストの第一の目的はパフォーマンスの計測であって、パフォーマンスの向上はまた別の話。
そのあたりの線引きを意識しておかないと無駄に負荷テストを繰り返して時間を浪費してしまいかねない。

スロークエリはダメ、絶対

ごくまれにしかアクセスされないページにひとつスロークエリが潜んでいるだけで一気にパフォーマンスが半減したりする。(実のところ本当に50%減とかする)
高負荷時にはひとつの小さな傷が致命傷になりかねないという話。

負荷テストを要するようなシステムではスロークエリは致命的なバグと同列と言っていい。

また、そうした重箱の隅に潜んでいるスロークエリをあぶり出すためにもシナリオはすべての処理を網羅している必要がある。

追記

– 手順の項にかける負荷の規模についてなど追記。

ほか何か思いついたら適宜追記していくかも。

ウェブアプリの負荷テストについてのメモ” に対して2件のコメントがあります。

  1. この記事はとても読みやすくて、勉強になりました。Jmeterなどのツールは単独テストとしてはいいけど、限界があります。例えば、httpプロトコル上でjavascriptなどの実行が不可能。最近クラウドを使って本物のブラウザーで実行出来る負荷テストのサービスが実現されました。詳細はhttp://www.browsermob.com/

  2. akahige より:

    ありがとうございます。
    また負荷テストする機会があれば検討してみますね。

コメントは受け付けていません。