Azure Storage に添付ファイルをアップロードする処理を持つ ASP.NET Core MVC(.NET Core) アプリを、 Azure App Service にデプロイしてベンチマークをとってみたら、 スケールアウトやスケールアップしても思ったようにパフォーマンスが上がらなくて、 ボトルネックを調べることになった。 モニターでメトリクスを確認してみたが、App Service Plan の CPU パーセンテージは 30% 程度だし、 メモリも 40% でほぼ一定。SQL Database も使ってはいるが、DTU は 50% 未満でまだ余裕がある。 なのに遅い。
モニタを眺めていてもボトルネックが分からなかったので、Application Insights と、その Profiler を導入してみた。 Application Insights の Profiler でホットパスを確認したところ、AWAIT_TIME で結構時間を食っていた。 AWAIT_TIME は Task を await してから復帰するまでの時間を表しているらしい。 で、肝心の await しているものが何かというと、Azure Storage へのファイルのアップロード。 Azure Storage には 1 ストレージアカウントの IOPS に上限があるので、最初これに引っかかっているのかと思った。 ただ、App Service をスケールアウトするとパフォーマンスが上がっていくので、これが原因とは考えにくい。
Azure Storage へのアップロードには Microsoft.WindowsAzure.Storage を使っているが、 内部では REST API を呼び出しているはず。 外部への通信が詰まっているのかもと思い、情報を探し回ったら、下記の古い記事を見つけた。
ファイル・ダウンロード時の最大同時接続数を変更するには?[C#、VB] - @IT
ServicePointManager.DefaultConnectionLimit
のデフォルトが 2 なのは知っていたが、
『外部からアプリケーションへの接続』ではなく『アプリケーションから外部への接続』だったのか。
勘違いしていた。
もし、.NET Core にもこの設定があって、デフォルト値が 2 のままなら、こいつが怪しい。
試しに、下記のように同時接続数の上限を変更してデプロイし直してみた。
// ASP.NET Core アプリケーションから外部のサービスを呼び出すときの // 同時接続数を増やす。 ServicePointManager.DefaultConnectionLimit = int.MaxValue; ServicePointManager.Expect100Continue = false;
ベンチマークをとったところ、40% 以上速くなった。 外部サービスへの通信が詰まっていたのが原因だったようだ。 これでめでたしめでたし…かと思いきや、また新たなボトルネックに遭遇。 調査はまだ続くみたいだ。とほほ。