ASP.NET Core 2.2 と同時にリリースされた ANCM v2 が +400% パフォーマンス改善したと書かれていたので、実際どのくらいまで頑張れるのか調べたくなりました。
ブログにあった +400% という数値は恐らく物理マシンを使っているので、実際に Azure 上の一般的な構成で動かした時にはそんな数値は出ないと思っていますが、IIS と Kestrel 間でのオーバーヘッドは無視出来ないものなので、App Service を使って実際の値を調べました。
はじめに
テストの条件は以下の通りです。インスタンスは 1 台で Windows は複数のサイトを 1 Service Plan にホストしているので、ANCM のバージョンとホスティングモデル以外は全く同じになっているはずです。
- 同じプロジェクトを使用 (Core MVC テンプレそのまま)
- Premium V2 の Medium (P2V2)
- West US 2
- Windows は Run From Package / Linux は Docker
- Load Test は West US / Warmup 設定あり
Run From Package は便利だから使っていますが、ストレージに足引っ張られるのも嫌だったという理由もあります。Linux では使えないので Docker を使っていますが、テストを行う前に 10 秒間のウォームアップ設定を入れているので、そこまで大きな差は出ないはず。
今回は以下の視点でテストを行っています。インスタンスサイズでの比較は面倒だったのでしませんでした。
- ANCM v1 と v2 での違い
- OutOfProcess と InProcess での違い
- Windows と Linux での違い
個人的には Windows と Linux での違いが気になっていたので追加で試しました。
一応は Kestrel で直接受けた場合には、Windows の方が Linux より速いというベンチマーク結果が Power BI で公開されていますが、App Service で使う場合にはどのくらい差があるのか疑問でした。
Azure DevOps の Load Test を使っていろんなパターンの負荷をかけて、503 エラーが出る前ぐらいの数値を拾ってきました。あくまでも P2V2 かつテンプレそのままの数値と考えてください。
ANCM v1 OutOfProcess vs ANCM v2 OutOfProcess
これまで通り dotnet のプロセスが w3wp とは別に立ち上がって、Kestrel で通信を受けるパターンですが、v1 と v2 で特に差はないようです。誤差ぐらいの違いしか出ていないです。
ASP.NET Core MVC 2.2 は P2V2 で大体 1k RPS ぐらいまで単純なページなら返せるのは、結構頑張っている感じがあります。RPS のグラフがギザギザになってるのは少し疑問です。
特に ANCM v1 はスループットが不安定ですし、v2 が出た今は使う必要はないでしょう。
ANCM v2 OutOfProcess vs ANCM v2 InProcess
気になっていた In-Process Hosting のパフォーマンスです。これまでの Out-Of-Process と比較して良好なパフォーマンスが出ています。安定したスループットが出せているのも良いです。
IIS と Kestrel 間で発生していた HTTP のオーバーヘッドが無くなった効果が出ているということでしょう。*1
これまでは IIS が受け取ったパース済みリクエストを、再度 HTTP に組み立てて後ろに流していたので当然とは言えますが…。とりあえず InProcess がデフォルトなのでそのまま使えば良いです。
Linux Docker vs ANCM v2 InProcess
最後は実質的に Linux と Windows の比較になるやつですが、実際は App Service のアーキテクチャ的に Linux より Windows の方がわずかに有利になっているので、どのくらいの差が付くのかという確認です。
結果としては ANCM の OutOfProcess よりは良い数値が出ました。スループットも安定しています。
ANCM v2 で InProcess がリリースされていなければ、ASP.NET Core は App Service の Windows より Linux を使った方がパフォーマンスが良いという現実だったようです。
とはいえ、普通に 1.3k RPS を 1 台の P2V2 で捌けているのは優秀ですね。もし Web App for Containers が TCP ではなく Unix Domain Socket に対応すれば、また結果は大きく変わる気がします。
*1:ネイティブ <=> C# でのマーシャリングコストは発生しているはず。