負荷試験の基礎の基礎

# はじめに

ECサイトやブログ、どこぞのサービスの公式サイトなどのWebサービスでも、ゲームやアプリなどのAPIでも、Webシステムを開発する上で欠かせない負荷試験。
だけど大半がリリース前に1度しか行わないため、実施に手間取ったり忘れがちだったりします。

そこまで詳しいわけではないですが、目的や手段など個人的な所感含め簡単にですが書いてみようと思います。


# 負荷試験はなぜやるのか

まず一番の目的は負荷対策が適切にできているかという点だと考えています。

すごくいいサービスを作ったとしても、人気が出てアクセスが増えた時にそのサービスが使えなかったら意味がありません。
安定した運用を行うためには、リリース前になるべく理想的なサーバの状態にする必要があります。
そのためにはボトルネックとなる部分を探し、サーバ構成や実装をチューニングする必要があります。
高負荷になることで判明するボトルネックを洗い出すためにも負荷試験は必要だと考えられます。

AWSなどを使用していると簡単にサーバ台数を増やしたり、スペックアップすることができるため、それで解決できてしまうことも多いです。ですが当然コストも増えます。端的に言えば「お金で解決」です。
当然ですが、Webシステムを運用する上で、低スペック・少ないサーバでなるべく多く・早くリクエストを処理できることが望ましいです。
お財布にも優しいし運用上管理する担当者にも優しいです。つまり地球に優しいです。

また、実施することで、これだけのアクセスに耐えられる構成・実装だという証明にもなります。


# 準備

負荷試験を実施するにあたって、まず何をしたらいいのか

### 目標値・期待値を決める（想定する）

負荷試験の指標はいろいろあります。
リクエスト数・レスポンスタイム・エラー率・スループット・CPU使用率・・・などなど。

あくまでも例えですが、
・サーバスペックや台数などから、1台あたりどれくらいのリクエストが捌けるか（構築したサーバの限界値確認）
・想定される利用者数（アクセス数）から、秒間での最大アクセス数を試算し捌けるか
・全リクエストの95%以下を1秒未満のレスポンスタイムで捌けるか
・エラー率1桁内で捌けるか
・上記の条件をCPU使用率50%以内で捌けるか
などなど、いろいろな視点から見る必要があります。

要件や想定される利用者数・サービスによってまちまちなので、
案件ごとに相談して決めましょう。

### 負荷試験ツールを用意する

負荷試験ツールもいろいろあります。

・Apache JMeter
http://jmeter.apache.org/
GUIツールで細かいシナリオを作成できます。
実行はコマンドラインでも可能です。
無料です。
自分は基本的にはこれを使っています。

・curl-loader
http://curl-loader.sourceforge.net/
コマンドラインのみの負荷試験ツールです。
無料です。

・Load Impact
http://loadimpact.com/
Webサイトから実行できる負荷試験ツールです。
一部無料ですが、基本有料です。

他にもいろいろあります。
今後いくつか試してみようとは思っています。

### シナリオを作成する

一番時間のかかる作業です。
リクエスト数の設定から1つのリクエストの細かい設定まで行います。

JMeterを例に上げますが、
・どのくらいの間隔でスレッドを生成するかを設定したり
・1スレッド何回ループさせるかを設定したり
・接続先、プロトコル、メソッド、ポートなどの環境設定を設定したり
・HTTPリクエストのヘッダ情報、クッキーなどの設定したり
・会員登録があるサイトなどでは認証情報を設定したり
・1ループごとに違うユーザにするために乱数を設定したり
・ifコントローラで条件分岐させたり
・ランダムコントローラでどれか一つのリクエストを実行したり
・リクエストパラメータを細かく設定したり
・設定値やリクエストをcsvから読み込んだり
・試験結果の出力を設定したり
・プロキシ使って自動でリクエスト作ったり（できるらしい）

機能が多すぎてキリがないですし、全く使いこなせてないと思っています。
効率よくシナリオ作成することが今後の課題と考えています。

Webサービスのシナリオ作成をする上で自分が注意している点は、
実際のユーザが操作するであろう順番にリクエストを実行するようにシナリオを作成するよう心がけています。
「トップページ→会員登録ページ→会員登録処理→会員登録完了ページ→トップページ」
のような順番で実行するようにします。
また、webサイトの場合は、同じページにアクセスが集中することは少ないと想定されるため、1処理に偏らないようにしたりします。（サイトの構成・実装にもよります）
APIの場合は、逆に1箇所に集中させてシナリオを作成して負荷をかけたりします。

実際のJMeterのシナリオの作り方も解説しようと思ったのですが、ボリュームが多くなりすぎてしまいそうなので、今回は割愛します。
別の機会があればそちらも書いてみようと思います。

### その他
サーバの監視ツールを導入したり、DBにスロークエリを出力するように設定しましょう。
それ以外にもアクセスログやシステムのログを監視できるようにしておきます。
正しく負荷がかけられているか、問題が起きた時に調査ができる環境になっているかなど、結果を確認する際に必要になってきます。


# 実施

JMeterの場合、GUIツールからも実行ができます。
ただ、高負荷をかけようとすると、当然ですがリクエストを投げる側にも負荷がかかります。
そのためローカルのPC上だと期待値が出せない場合が多いです。
AWSなどを利用している場合はLambdaなどを使用してリクエストを投げる側も分散しましょう。


# 結果確認

サーバの監視ツールなどで結果を確認します。
JMeterにも結果の出力機能はありますが、リクエストに対してだけになるので注意が必要です。
確認が必要な項目に対して、正しく確認が取れるように実施前に準備をすることが大事になります。

目標値・期待値に達していない場合は、どこにボトルネックがあるかを探していきます。

## ボトルネックになりやすい箇所

### レスポンスタイムの遅延

負荷が上がるにつれて、レスポンスタイムが遅くなっていくことがよくあります。
原因は様々です。
どこで詰まっているか調査する必要があります。

例えば、
・ロードバランサーの設定
・Nginx/Apacheの設定
・DBの設定（特にコネクション数）
・メモリの使用量
など、インフラ面・実装面での調査・調整が必要になります。

### 特定のページ（処理）だけ重い

静的なコンテンツのリクエストや、selectだけしかしていない処理などはすごく良いフォーマンスが出ているのに、
特定の処理だけやけに時間がかかっている、などもよくあります。

大半がDB周りの実装が原因になることが多いと思います。
・複数インサートする処理なのに、1件ずつインサートしてる
・インデックスが適切に設定できてない
・
そもそもの設計や処理を見直す必要もあります。

### DBのデッドロック
トランザクションが張れていなかったり、同じテーブルに対して複数箇所からインサート・アップデートを行うとよく起きます。
低負荷だと起きづらいため負荷試験中に判明することが多いです。
実装面の見直しが必要です。


# おわりに

負荷試験を実施することへのメリットは数多くあります。
むしろデメリットなんてないと言っていいと思います。
手間や時間はある程度どうしてもかかってしまいますが、軽視せずに負荷対策がしっかり行えているか確認するためにも負荷試験は実施しましょう！（自分への戒め）
（手間を省けるよういろいろ考え中・・・）

駆け足感が否めないですが、続編やるとしたらシナリオの作り方や結果の確認方法など書いてみようと思います。