次の方法で共有


Azure Functions における同時実行

この記事では、Azure Functions におけるイベントドリブン トリガーの同時実行制御の動作について説明します。 また、静的なコンカレンシー モデルと動的なコンカレンシー モデルも比較します。

Functions では、任意の関数の複数の実行プロセスを、1 つのコンピューティング インスタンス上で同時に実行することができます。 たとえば、負荷増大に対応するため複数のインスタンスにスケールアウトしている関数アプリに、3 つの異なる関数がある場合を考えてみましょう。 このシナリオでは、各関数は、個々の呼び出しに応じて 3 つのインスタンスすべてで実行されます。また、どのインスタンスも、同じ種類であれば複数の呼び出しを処理できます。 1 つのインスタンス上で関数が複数実行される際には、同じメモリ、CPU、接続リソースが共有されることに注意してください。 各インスタンスにおいて複数の関数実行を同時に実行できることから、各関数には同時実行数を管理する方法が必要になります。

アプリが動的スケール プラン (従量課金、Flex 従量課金、または Premium) でホストされている場合、ホストは、受信イベントの数に基づいて、関数アプリ インスタンスの数をスケールアップまたはスケールダウンします。 詳細については、「イベント ドリブン スケーリング」を参照してください。 関数を Dedicated (App Service) プランでホストする場合は、インスタンスを手動で設定するか、自動スケーリング スキームを設定します。

また、インスタンス上の実行のコンカレンシーも、これらのスケールの決定に直接影響します。 動的スケール プランのアプリがコンカレンシーの制限値に達した場合、受信需要に対応するためスケーリングが必要になる場合があります。

Functions には、コンカレンシーを管理する主に 2 つの方法が用意されています。

静的な同時実行制御

既定では、ほとんどのトリガーがホストレベルの静的構成モデルをサポートしています。 このモデルでは、トリガーの各種類に、インスタンスごとのコンカレンシー制限があります。 ただし、ほとんどのトリガーでは、その種類のトリガーに対して特定のインスタンスごとのコンカレンシーを要求することもできます。 たとえば、Service Bus トリガーの場合、host.json ファイルMaxConcurrentCallsMaxConcurrentSessions の両方の設定が含まれています。 これらの設定が組み合わさることで、インスタンスごとに、各関数で同時に処理するメッセージの最大数を制御します。 他のトリガーの種類には、インスタンス間で負荷分散を行うためのメカニズムが組み込まれています。 たとえば、Event Hubs と Azure Cosmos DB の両方で、パーティションベースのスキームが使用されています。

コンカレンシーの構成に対応した種類のトリガーの場合、設定内容は実行中のすべてのインスタンスに適用されます。 これにより、各インスタンスでの関数のコンカレンシーの最大数を制御することができます。 たとえば、関数が CPU またはリソースを大量に消費する場合は、インスタンスを正常な状態に保つためにコンカレンシーを制限したり、負荷の増大に対処するためにスケーリングを使用したりすることができます。 同様に、スロットルされているダウンストリーム サービスに対して関数が要求を行っている場合も、ダウンストリーム サービスのオーバーロードを避けるためにコンカレンシーの制限を検討する必要があります。

HTTP トリガーのコンカレンシー

Flex 従量課金プランにのみ適用されます (プレビュー)

Flex 従量課金プランでは、すべての HTTP トリガー関数がまとめてスケーリングされます。 詳細については、「関数ごとのスケーリング」を参照してください。 以下の表は、任意のインスタンスにおける構成済みのインスタンスのメモリ サイズに基づく HTTP トリガーの既定のコンカレンシー設定を示しています。

インスタンスのサイズ (MB) 既定のコンカレンシー*
2048 16
4096 32

*Python アプリの場合、すべてのサイズについて、既定の HTTP トリガーのコンカレンシー数は 1 です。

ほとんどの場合、この既定値で問題ないため、初めはこれを使用します。 任意の HTTP 要求数において、HTTP のコンカレンシー数を増やすことで、HTTP 要求の処理に必要なインスタンスの数は減少します。 同様に、HTTP のコンカレンシー数を減らすと、同じ負荷の処理により多くのインスタンスが必要になります。

HTTP のコンカレンシーの微調整が必要な場合は、Azure CLI を使用してこれを行えます。 詳細については、「HTTP コンカレンシーの制限を設定する」を参照してください。

前の表の既定のコンカレンシーの値は、HTTP のコンカレンシー設定を独自に行なっていない場合にのみ適用されます。 HTTP のコンカレンシー設定を明示的に行なっていない場合、インスタンスのサイズを変更すると、既定のコンカレンシーは表のとおりに増加します。 特定の HTTP コンカレンシー値を設定すると、インスタンスのサイズを変更してもその値は維持されます。

最適な静的コンカレンシーを決める

静的なコンカレンシーを構成することで、関数のスロットリングなどの特定のトリガー動作を制御することができますが、これらの設定の最適な値を判断することは困難な場合があります。 一般的には、ロード テストを反復して行うことで、許容できる値を導き出さなければなりません。 特定の負荷プロファイルに適した一連の値を決定したとしても、接続済みサービスから届くイベント数は日によって変化することがあります。 この変動性は、多くの場合、アプリが最適でない値で実行されている可能性があることを意味します。 例えば、週の最終日には、関数アプリでは特に負荷の高いメッセージ ペイロードを処理するため、同時実行数を低くスロットルする必要があるとします。 しかし、週の残りの期間はメッセージのペイロードが単純なので、その週の残りの期間は同時実行のレベルを高くすることができます。

理想的なシステムは、インスタンスでできるだけ多くの作業を処理できるようにしながら、各インスタンスの健全性を保ち、レイテンシーを低くすることができることで、これは、動的な同時実行制御の目的でもあります。

動的な同時実行制御

Functions では、同じプランで実行されているすべての関数アプリの同時実行制御の構成を簡略化する動的な同時実行制御モデルが提供されるようになりました。

Note

動的な同時実行は、現在、Azure Blob、Azure Queue、および Service Bus トリガーのみでサポートされており、以下の拡張機能のサポート セクションに記載されているバージョンを使用する必要があります。

メリット

動的な同時実行制御を使用すると、次のような利点があります。

  • 構成の簡略化: トリガーごとの同時実行の設定を手動で決定する必要がなくなりました。 システムは、ワークロードに最適な値を時間をかけて学習します。
  • 動的な調整: 同時実行はリアルタイムで動的に上下に調整されるため、システムは時間の経過と共に変化するロード パターンに対応することができます。
  • インスタンスの正常性保護: ランタイムは、関数アプリのインスタンスが快適に処理できるレベルまで同時実行を制限します。 これにより、アプリが必要以上の作業を引き受けて過負荷になることを防ぎます。
  • スループットの向上: 個々のインスタンスが迅速に処理できる以上の作業を引き受けることがないため、全体的なスループットが向上します。 これにより、複数のインスタンス間でより効果的に負荷分散することができます。 高負荷を処理できる関数の場合は、既定の構成値以上にコンカレンシー数を増やすことで、スループットを高めることができます。

動的な同時実行制御の構成

動的な同時実行制御は、host.json ファイルでホスト レベルで有効にすることができます。 これを有効にすると、この機能に対応したバインド拡張機能のコンカレンシーのレベルは、必要に応じて自動的に調整されます。 こうした場合には、動的コンカレンシー設定が、手動で構成されたコンカレンシー設定をオーバーライドします。

既定では、動的な同時実行制御は無効になっています。 動的な同時実行制御が有効になっている場合、各関数の同時実行数は 1 から開始され、ホストによって決定される最適な値まで調整されます。

関数アプリで動的な同時実行制御を有効にするには、host.json ファイルに以下の設定を追加します。

    { 
        "version": "2.0", 
        "concurrency": { 
            "dynamicConcurrencyEnabled": true, 
            "snapshotPersistenceEnabled": true 
        } 
    } 

SnapshotPersistenceEnabledtrue の場合 (既定設定です)、学習された同時実行数の値が定期的にストレージに保存されるため、新しいインスタンスは 1 から開始して学習をやり直すのではなく、これらの値から開始されます。

同時実行マネージャー

動的な同時実行制御を有効にすると、裏側では、同時実行マネージャー プロセスがバックグラウンドで実行されます。 このマネージャーは、CPU とスレッドの使用率などのインスタンスの正常性メトリックを常に監視し、必要に応じてスロットルを変更します。 1 つまたは複数のスロットルが有効になっている場合、関数の同時実行数が、ホストが正常な状態になるまで減らされて調整されます。 スロットルが無効になると、同時実行数の増加が許可されます。 これらのスロットルに基づいて、必要に応じて様々なヒューリスティックを使用して同時実行数が上下に調整されます。 時間の経過と共に、各関数の同時実行数が特定のレベルに安定します。

同時実行のレベルは、個々の関数ごとに管理されます。 そのため、システムは、同時実行数を少なくする必要があるリソース集中型の関数と、高い同時実行数を処理できる軽量な関数との間でバランスを取ることができます。 各関数の同時実行数のバランスを取ることで、関数アプリ インスタンスの全体的な正常性を維持することができます。

動的な同時実行制御を有効にすると、ログに動的な同時実行制御に関する判断が表示されます。 たとえば、さまざまなスロットルが有効になっていて、関数ごとに同時実行が上下に調整されたときに、ログが表示されます。 これらのログは、トレース テーブルの Host.Concurrency ログ カテゴリに書き込まれます。

拡張機能のサポート

動的な同時実行制御は、ホスト レベルで関数アプリに対して有効化され、動的な同時実行制御をサポートするすべての拡張機能はそのモードで実行されます。 動的な同時実行制御を行うには、ホストと個々のトリガー拡張機能との連携が必要です。 動的な同時実行は、次の拡張機能の一覧にあるバージョンのみでサポートされています。

拡張子 Version 説明
Queue Storage バージョン 5.x (ストレージ拡張機能) Azure Queue Storage トリガーには、独自のメッセージ ポーリング ループがあります。 静的な構成を使用する場合、同時実行は BatchSize/NewBatchThreshold 構成オプションによって制御されます。 動的な同時実行を使用する場合、これらの構成値は無視されます。 動的な同時実行はメッセージ ループに統合されるため、1 回のイテレーションでフェッチされるメッセージの数は動的に調整されます。 スロットルが有効になっている (ホストが過負荷になっている) 場合は、スロットルが無効になるまでメッセージ処理は一時停止されます。 スロットルが無効になると、同時実行数が増加します。
Blob Storage バージョン 5.x (ストレージ拡張機能) 内部的に、Azure BLOB ストレージ トリガーでは、Azure キュー トリガーで使用されるのと同じインフラストラクチャが使用されます。 新しい、または更新された BLOB を処理する必要がある場合は、プラットフォームで管理されているコントロール キューにメッセージが書き込まれ、そのキューは、キュー トリガーに使用されるのと同じロジックを使用して処理されます。 動的な同時実行が有効になっている場合は、そのコントロール キューの処理に対する同時実行は動的に管理されます。
Service Bus バージョン 5.x 現在、Service Bus トリガーでは、3 つの実行モデルをサポートしています。 動的な同時実行制御は、これらの実行モデルに次のような影響を与えます。

トピックまたはキューのシングル ディスパッチ処理: 関数を呼び出すたびに、1 つのメッセージが処理されます。 静的構成を使用する場合、コンカレンシーは MaxConcurrentCalls 構成オプションによって制御されます。 動的な同時実行制御を使用する場合、構成した値は無視され、同時実行は動的に調整されます。
トピックまたはキューのセッション ベースのシングル ディスパッチ処理: 関数を呼び出すたびに、1 つのメッセージが処理されます。 トピックまたはキューのアクティブなセッションの数に応じて、各インスタンスは 1 つ以上のセッションをリースします。 セッション内の順序を保証するために、各セッションのメッセージは順番に処理されます。 動的なコンカレンシーを使用しない場合、コンカレンシーは MaxConcurrentSessions 設定によって制御されます。 動的な同時実行が有効になっている場合、MaxConcurrentSessions は無視され、各インスタンスで処理されるセッション数は動的に調整されます。
バッチ処理: 関数を呼び出すたびに、MaxMessageCount 設定によって制御されるメッセージのバッチが処理されます。 バッチ呼び出しは直列であるため、バッチによってトリガーされる関数の同時実行数は常に 1 つであり、動的な同時実行制御は適用されません。

次のステップ

詳細については、次のリソースを参照してください。