最近は Azure Functions でのスケーリングに関する質問をよくされるのと、自分自身が仕事で効率良くスケーリングが可能な Function 実装を行う必要が多かったのでまとめておきます。今回はスケールアップではなく、スケールアウトの方を指しています。
事前に以下のドキュメントを読んでおいた方が理解が早いです。特に Azure Functions は Web Apps とは異なるスケーリングの仕組みを持っているので、若干仕組みが特殊です。
多少混乱しやすいですが Azure Functions は 3 箇所でスケーリングに関する設定を行えます。昔は設定が少しわかりにくかったですが、最近はポータルでの設定が分かりやすくなりました。
結果としては Function App のインスタンス数 * Function の同時実行数の結果が、この Function App で実際に同時に実行される Function の回数になります。
- App Service Plan のインスタンス数
- 実行に使われる仮想マシンの数に相当する
- Function App 単位のインスタンス数
- App Service Plan のインスタンス数を上限にアプリ単位で設定が可能
- インスタンス単位の Function 同時実行数
- デフォルトで Runtime は設定された範囲で Function を同時に実行する
Consumption や Premium Plan を使っていると Function の同時実行数を気にしなくてもガンガンスケールしていきますが、インスタンスサイズや処理内容によっては同時実行数を変更した方が全体のスループットが改善します。この辺りは Application Insights や Azure Monitor を使って日々モニタリングします。
高速にスケーリングが行われると言ってもそれは App Service Plan 単位での話なので、Function の実装が非効率な場合は思ったようにスケールされずに、コストばかりがかかるようになります。CPU とメモリを効率よく使用する実装を行う必要があります。
それぞれ 3 箇所でのスケーリング設定についておさらい程度にまとめておきます。
App Service Plan のインスタンス数
単純に実行される仮想マシンを増やすので、全体としてのスループットが向上します。Consumption は特殊なので設定自体が存在しませんが、Premium Plan と App Service Plan の場合は設定可能です。
Premium Plan
Azure Portal の Scale out を選ぶと Plan Scale out という項目で Maximum Burst*1 が設定できます。
Minimum Instances はグレーアウトして設定出来ませんが、Function App の設定から自動計算されるのでデフォルトの 1 のままで良いです。
注意点としては Premium Plan の場合は Maximum Burst == Function App のインスタンス数にならないことです。Function App 単位で独立したスケールが行われるので、実稼働インスタンス数はバラバラです。
App Service Plan
お馴染みの App Service Plan の場合はこれまでと同じで、手動でインスタンス数を設定するか Azure Monitor ベースの Autoscale を使うかのどちらかです。Azure Monitor ベースなのでスケールは多少遅いです。
既存の Web Apps と共存されることが出来るのでコストを抑えられるのがメリットです。後はタイマーで長時間稼働するような、リソースは必要だけど動的なスケーリングが必要ない場合に使うのが良いです。
Function App 単位のインスタンス数
App Service Plan で稼働させる場合は App Service Plan のインスタンス数 == Function App のインスタンス数が成り立ちますが、Premium Plan と Consumption Plan では Function App 単位で自由にスケールされるので、それぞれ個別に設定出来るようになっています。
Consumption Plan
シンプルなのが Consumption Plan の設定です。基本は 0 インスタンスから最大 200 までスケールされますが、最近になって最大インスタンス数を設定出来るようになりました。
従量課金なので制限してもしなくても、結局は実行数が同じなら課金は変わらないです。しかし相手が RDB などのコネクション数に上限のあるリソースの場合に、この設定を上手く使うことで問題を回避できます。
Premium Plan
Premium Plan の場合は Always Ready Instances という項目が追加されていて、設定した数だけ Function App を常に立ち上げておくことが出来ます。これは課金に影響してくるので注意深く設定しましょう。
後の設定は Consumption Plan と同じなので説明は省略しておきます。
これ以外にも ARM 上でのみ設定可能な項目として preWarmedInstanceCount
というものがありますが、これが課金にどう影響するのかを確認中なので一旦は省略しておきます。
インスタンス単位の Function 同時実行数
最後は 1 インスタンスでの Function 同時実行数の設定です。これはアプリ側の設定になるので host.json
で指定するようになっています。使用頻度が高そうなものをピックアップしています。
強く注意しておきたい点として、やみくもに増やせば良いというものではないことです。Function の実行でリソースがどのくらい使用されているのかを把握しながらやらないと意味がないです。
Durable Task
Durable Functions は実行単位として Activity と Orchestrator の 2 つが存在するので、それぞれで同時実行数を設定出来るようになっています。
大量に Activity や Orchestrator の Task
を作成して Task.WhenAll
で完了を待つパターンが多いはずなので、リソース使用率を確認しながら調整が必要です。
maxConcurrentActivityFunctions
maxConcurrentOrchestratorFunctions
デフォルト値が CPU 数 * 10 なので、ネットワークなどの I/O 待ちが多い処理の場合は CPU がスカスカなことも多そうです。Application Insights と組み合わせて上手く調整していきましょう。
Event Hubs
大量データを処理するものと言えば Event Hubs が代表的です。Queue に近いので 1 回で処理するバッチサイズという形で同時実行数を設定出来るようになっています。
maxBatchSize
prefetchCount
デフォルトだと maxBatchSize
は 10 なので、そのまま使っていると思ったようにスループットが上がらずに悩まされそうです。CPU コア数に比例した値の方が良さそう。
この辺りの設定は Azure Functions の Binding 固有のものではなく、Event Hubs SDK に渡す値なだけなので、適切な値は Event Hubs のドキュメントを読んだ方が分かりやすいです。
Http
ちょっと意外なのは Http 周りですが、Azure Functions は大量にリクエストが投げられた場合には 429 を返すことが出来るので、スロットリングを簡単に実装出来ます。
maxConcurrentRequests
maxOutstandingRequests
ただし Premium Plan や App Service Plan ではデフォルトが無制限なので基本は全て受け切ります。
スロットリングの実装の場合は dynamicThrottlesEnabled
という CPU 使用率を見て 429 を返すオプションもあるので、結構便利に使えます。
Queue Storage
何だかんだで未だに使う機会が多いのが Queue ですが、元々バッチで処理する前提の API になっています。なので Azure Functions でも batchSize
を指定できるようになっています。
batchSize
newBatchThreshold
batchSize
のデフォルト値は 16 で、最大でも 32 までしか設定できませんが、これは Queue API の制限なので増やすことは出来ません。
Azure Functions の実装としてはバッチで受信した未処理メッセージ数が newBatchThreshold
を下回れば、新しくメッセージをバッチで取得するので、最大同時実行数は 32 + 16 = 48 になります。この辺りの設定はちょっとわかりにくいです。
Service Bus
最後は Service Bus ですが、最近は個人的に使わなくなってきたのでさらっと行きます。基本はこれも Queue に近いので、設定名は違いますがやっていることは同じです。
maxConcurrentCalls
maxConcurrentSessions
重要なのは maxConcurrentCalls
の設定で、デフォルトは 16 なので処理に合わせて変更すれば、より良いスケールが行えるでしょう。maxConcurrentSessions
はデフォルト値が大きいのでそのままで良いです。
Durable Function 以外は CPU コア数によって同時実行数が変化しないので、2 コア以上の Tier を使ってもスループットが上がりにくいのは注意しておいた方が良いです。
そういったことを把握するためにも Application Insights と Azure Monitor が必須というわけです。
*1:要するにスケーリング時の最大インスタンス数のこと