これだけは知っておこう負荷試験 ~その1 基本とお試し試験~
記事の概要
負荷試験はシステム運用において避けて通れないタスクであるが難易度が高いタスクでもある。
本記事ではまず、実際にWordpressに対して簡単な負荷試験を行いながら、 負荷試験における基本的な観点を整理していく。
負荷試験の主な目的
負荷試験は何のために行うのだろうか? 主な観点としては下記のような項目が挙げられる。
- 負荷に耐えうる構成か?
- 要件に対して最適な構成になっているか?
- 突然スパイクしたときにも自動でスケールし耐えられる構成になっているか?
- 通常時に必要以上にインフラリソースを確保していないか?
- スケール特性を把握する
- まずどこにボトルネックが来て、どこをチューニングすればシステムがスケールするかを確認する
負荷試験の大事なルール
必ずどこかがボトルネックになっている状態を作ること
スコープを絞ってステップごとに区切って実施すること
- 問題の原因特定を効率的に行うことができるため、少しずつ負荷のかけ方を変えながら実施する
ネットワーク的に近いところから攻撃する
最初は最小の構成 & 自動スケールしないようにして実施する
負荷試験をする上で参考にする性能指標
負荷試験実施の際は、下記指標を確認していき、問題があった場合はCPU使用率やメモリ使用率、コネクション数などの細かい指標を追っていくことになる。
実際の負荷試験のステップ例
攻撃サーバのセットアップ
- 最大攻撃性能を把握することで攻撃のパフォーマンスが十分に発揮できているかを確認する。
フレームワークの素の性能の把握
DBへの参照を含めた性能の把握
- DBとの接続方法、クエリの実行方法などが適切に設定、実装されているかを確認する。
- 前工程と比較してDB参照に大幅な劣化がある場合は、下記観点で確認する。
- Web, DB, 攻撃サーバで負荷が正しくかかっているかを確認する
- バッファプールにデータが乗り切っているか、キャッシュヒット率はどのくらいか
- コネクションを永続化できているか確認する(コネクションプーリングの設定)
- アプリケーション側でN+1やスロークエリなどが出ているか
DBへの更新を含めた性能の把握
- DBとの接続方法、クエリの実行方法などが適切に設定、実装されているかを確認する。
- 前工程と比較してDB参照に大幅な劣化がある場合は、下記観点で確認する。
- Web, DB, 攻撃サーバで負荷が正しくかかっているかを確認する
- 必要以上に偏ったユーザデータのシナリオになっていないか? ※例えばテストユーザを一人だけにして更新テストを行う場合、ロックの傾向が偏ってしまい、本番のシナリオと剥離してしまう。
- 不必要なロック、トランザクション分離レベルなどを見直しつつ調整
外部サービスとの通信を含めた性能の把握
- 外部サービスとネットワークを経由して通信しているケースの負荷シナリオ
- 自サービスの管轄外の場合、ここがボトルネックになりやすい
- 負荷をかける場合は、意図せず外部サービスに過負荷をかけてしまわないよう気をつける
実際の使用を想定したシナリオでの性能の把握
- 実際のユーザのシナリオを想定し、負荷をかける
- このシナリオでの負荷試験でしっかり想定どおりのパフォーマンスがでるかどうかを検証する
スケール特性試験
実践してみよう!
- このWordPressリソースを用いて試しに負荷試験の流れを学ぶ https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/
環境
この環境で出せる攻撃時スループットの上限値を知る
現時点で、MAXでどのくらいのスループットがでるのかを検証するため、 一番処理の軽い静的ファイルを返すエンドポイントに対し、 Apache Benchを使って負荷をかけてみる。 ネットワーク的な要因を排除した純粋なスループットを計測したいのでホストから実行する。 ネットワークはスループットをかなり落としてしまう要因になるので、実際の負荷試験においてもなるべくネットワーク的に近いところから試験することはかなり重要になってくる。
ab -n 20000 -c 200 -k http://10.108.252.89/readme.html
大体この数値がこの環境における攻撃時に出せる最大のスループットということになる。
Requests per second: 7711.03 [#/sec] (mean)
検証の妥当性
この結果が妥当であることをどのように判別すればよいだろうか? まず最初に見るべき観点は以下になる。
対象システムのCPU使用率が100%近くまで上がっているか?
- ※DBサーバへの負荷の場合はもう少し下がることが多い
攻撃サーバ側のCPU使用率は100%近くまで上がっているか?
- 余裕がある場合は、同時接続クライアント数が足りていない
極端に同時接続クライアントが多すぎる場合スループットには出ないが、レイテンシが極端に落ちる。(リクエストが実行されるまでの待ち時間も含まれてしまうため)
こうなると問題の切り分けが大変になってしまうので、同時接続クライアント数は多すぎず、少なすぎない状態で実施するのがベスト。
(十分に負荷がかかっているのに必要以上にクライアント数をあげない)
今回は静的ファイルのため、Webサーバ単体への負荷となり、WebサーバはCPU使用率が90%以上で張り付いていたため、 十分に負荷をかけられていると判断した。
Wordpressの実際のスループット
今度は静的ページではなく、MySQLへのアクセスを伴う実際のページにアクセスしてみる。
ab -n 20000 -c 200 -k http://10.108.252.89
スループットは下記まで落ち込んだ。
Requests per second: 30.93 [#/sec] (mean)
また、DBもWebもCPU使用率90%以上で張り付いているので負荷はしっかりかかっていると見て良さそうである。
DB側がボトルネックになっていそうなので、DBのPodをスケールアップしてみる。
DBをスケールアップしてみた後
もともとが1コアを割り当てていたので、2コア割り当てるようにしてみた。
kubectl describe node Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE --------- ---- ------------ ---------- --------------- ------------- --- default wordpress-5bbd7fd785-gswtm 0 (0%) 0 (0%) 0 (0%) 0 (0%) 22h default wordpress-mysql-88898b8ff-jhj9g 2 (50%) 2 (50%) 0 (0%) 0 (0%) 22h
ab -n 20000 -c 200 -k 10.108.109.63
両者ともにCPU使用率は90%以上で、スループットが純粋に向上した。
Requests per second: 70.14 [#/sec] (mean)
ただ、またもやDBもWeb側もCPUが90%以上になっているため、 まずDB側をスケールアップしないとスループットは上がらなさそうである。 今回はアプローチを変えてDBを一定時間キャッシュさせ、DBアクセスをしないようにしてみる。
DBキャッシュ適用後
DBキャッシュを有効にした結果、スループットが劇的に改善している。
Requests per second: 3120.29 [#/sec] (mean)
DB側のCPU使用率も一瞬はねたが、一気に下がった。 一方Web側は変わらずCPU使用率が90%超えであり、 ボトルネックがDBからWebに移ったのが分かる。
まとめ
ボトルネックがWeb側に移動したのでWeb側をスケールしたいところだが、ローカルの貧弱な環境だと限界なのでローカルでの試験は一旦ここまでとする。
基本的な流れをこのさきのステップも同じで、
を繰り返していくことになる。
次回はKubernetesにアプリケーションをデプロイし、複数ノード & 攻撃サーバも負荷対象システムもスケールできる環境で実際にやってみる。
~ TO BE CONTINUED ~