Heroku の Private Spaces で、Pre-warm して、負荷テストを実施してみる

# 要約
- pre-warm できてるか？は、dig で確認できます
- Private Spaces でも、たくさんの Dyno を使えます

# Heroku でどのくらいのトラフィックを捌けるのか？はココでは語らないのはご了承ください！
クラウドを利用すると、ウェブアプリケーションのパフォーマンス上限は、スケールアウトで柔軟（？！）に対応できるので、オンプレ時代と比較すると、厳密なサイジングはしていないかもしれませんが、やはり、上限は気になりますよね。ということで、Heroku で負荷テストしてみた話です。
ですが、実際の結果は、ココでは語りません。というのも諸条件の影響で結果が揺らぐ可能性があるのに、結果をこちらで書いてしまうと、その数字が一人歩きしそうで怖かったからです。実施したシンプルな負荷テストの方法は記しますので、興味があれば、実施してみてください。

# Dev center に記載されている Load Test Guidelines
Heroku の Dev center には、ロードテストする場合のガイドラインが明記されています。
> [Load Testing Guidelines](https://devcenter.heroku.com/articles/load-testing-guidelines)

正確な内容は、リンクを参照いただくとして、ざっとまとめると

### Common Runtime の場合
- 10,000 リクエスト/秒 以上の負荷をかけるなら、2営業日前までにサポートに連絡して承認とってね (10,000 リクエスト/秒 以下なら承認不要)
- 承認無しで、負荷テストしたら、ウェブアプリケーション止める可能性ありますよ
- 負荷テストで使えるのは Performance Dyno だけですよ

> 10,000 リクエスト/秒 = 60万 リクエスト/分 = 3,600万 リクエスト/時間 

ですので、Common Runtime 環境で、承認無しな状態においても結構な規模なウェブサイトをホストできそうだな。というのは、なんとなく思えるのではないでしょうか。次に、Private Spaces。

### Private Spaces の場合
- 特に事前承認は不要ですよ
- とはいえ、大規模な負荷をかける場合は、(AWSの)ELBをpre-warm するべきなので、サポートに連絡してね
- すべての Dyno Type で負荷テストできますよ
- でも 2 Dyno 以上たてといてね

という感じです。 pre-warm したら、どんな案配になるのか気になりますねー。ということで、リクエストしてみました。

# Private Space で ELB を Pre-warm してみる
では、Private Space では、どのくらい捌けるのか？というのをみてみるために、ELB の Pre-warm をリクエストすると、どうなるのか？というところのチェックをしてみます。

### まずは Pre-warm 無し
Pre-warm リクエストしていない状態で、Heroku アプリケーションの URL を dig してみるとこんな感じです。
![elb2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816/35aa128e-4171-dee7-9d33-ba1fd1698fcb.png)
少なくとも、2つのインスタンスがロードバランサーとして動いているっぽいことが確認できます。
### Pre-warm をリクエスト
負荷をかける日時・期間や、どのくらいの負荷をかけるのか？ということをサポートに（チケットで）伝え、Pre-warm してみた状態で、Heroku アプリケーションの URL を dig してみるとこんな感じになりました。
![elb8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816/9363e1bf-e52e-3b79-ba6f-05ce08194c89.png)
Pre-warm することで、ロードバランサーが、8つのインスタンスに拡張されました
#実際、負荷をかけてみた
###負荷をかけた環境
- Virginia の Private Spaces
- [loader.io](https://elements.heroku.com/addons/loaderio) の Pro Plan で負荷をかける
- nginx 1.16.1 / php 7.3.11
- [ウェブアプリケーションソースコード](https://github.com/masamis/simple-perf-test)
    - OK とだけ返す最小限の動的コード

実際に、loader.io を使って、負荷をかける場合、負荷をかけるウェブサイトを認識させるために、[App verification](https://devcenter.heroku.com/articles/loaderio#app-verification) の手順を事前に実施します。自分管理じゃないサーバーに勝手に負荷をかけられたりしたら、問題になるので、こういった手順は、どの負荷ツールでも必要になりますね。
###負荷のかけ方とその結果
以下の様な負荷のかけ方を実施しました。

| Dyno| Pre - warm |結果|備考|
|:--|:------:|:--|:--|
| Private S/M/L x 1 (dyno)       |  無し       |数千リクエスト/秒達成、Dynoサイズによりパフォーマンスは異なる |       Dyno サイズ毎の限界把握        |
| Private L x ｎ (dyno)           |   無し       |ロードバランサーが限界のタイミングで、Heroku Dashboard の Metrics の Routing Health で degraded が発生  | Dyno数によるパフォーマンス向上の状況把握、および、Pre-warm 無しのロードバランサーの限界把握      |
| Private L x n (dyno)           |         有り      |Pre-warm によるロードバランサー性能の向上を確認| pre-warm によるパフォーマンス向上の状況把握              |

結論から言えば、**10万リクエスト以上/秒**を想定していた大規模なウェブアプリケーションを Heroku 上でホストできる可能性が高く、少なくともウェブサーバーがボトルネックになる可能性は少ないということを、今回の負荷テストによって推測できました。

#悩んだ点
テストしている時に思うような結果が得られず、悩んでたことを記しておきます。
###原因は loader.io のパフォーマンス（と思われる)
5,000リクエスト/秒や、10,000リクエスト/秒といったテストの場合、予想通りの結果がかえってきていたのですが、20,000リクエスト/秒あたりから、挙動が不安定になり、loader.io でいくつかのエラーが発生しました。そのあたりが Heroku の限界なのか？冷や汗でましたが、Heroku 側でのエラーは発生していない状況。Dyno をいくら増やしても、ロードバランサーの Pre-warm 環境でも loader.io が予想している結果にならず悩んだのですが、loader.io を複数用意し、平行して走らせてみると挙動は安定。負荷ツール自体がボトルネックになるということをまったく予想しておらず、まったく疑わなかったのが大反省点でした。loader.io に限らず、クラウド環境であっても負荷テストツール側のパフォーマンス限界があることの意識は必要ですね。

#おまけ
いくつの Dyno が必要になるのか不明だったので、拡張できるだけ、利用可能な Dyno 数を増やしてみたので、スクショ貼って起きます！**197 Dyno !**（といいつつ、今回使った最大Dyno数は30程度でした)
<img width="1240" alt="スクリーンショット 2019-12-16 17.29.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816/cd8f00ba-6d51-4fd9-1e3f-f7f6848ab3bf.png">