Azure Functions における同時実行

この記事では、Azure Functions におけるイベントドリブン トリガーの同時実行制御の動作について説明します。 また、同時実行制御の動作を最適化するための新しい動的モデルについても説明します。

注意

動的な同時実行制御モデルは現在プレビューの段階です。 動的な同時実行制御のサポートは、特定のバインド拡張機能に限定されており、こちらも現在はプレビューの段階です。

Functions のホスティング モデルを使用すると、複数の関数呼び出しを 1 つのコンピューティング インスタンスで同時に実行することができます。 たとえば、スケールアウトして複数のインスタンスで実行している関数アプリに、3 つの異なる関数がある場合を考えてみましょう。 このシナリオでは、関数アプリが実行されている各 VM インスタンスで、各関数によって呼び出しが処理されます。 1 つのインスタンス上の関数呼び出しは、メモリ、CPU、接続など、同じ VM のコンピューティング リソースを共有します。 アプリが動的プラン (従量課金プランまたは Premium) でホストされている場合、プラットフォームは、受信イベントの数に基づいて、関数アプリ インスタンスの数をスケールアップまたはスケールダウンします。 詳細については、イベント ドリブン スケーリングに関するページを参照してください。 関数を Dedicated (App Service) プランでホストする場合は、インスタンスを手動で設定するか、自動スケーリング スキームを設定します。

各インスタンスでは、複数の関数呼び出しが同時に実行されることがあるため、各関数には、同時に処理する呼び出しの数を調整する方法が必要になります。

静的な同時実行制御

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

同時実行の構成がサポートされているトリガーの種類には、既定の動作があり、関数アプリの host.json ファイルで上書きすることができます。 これらの設定は、実行中のすべてのインスタンスに適用されるので、各インスタンスにおける関数の最大同時実行数を制御することができます。 たとえば、関数が CPU またはリソースを大量に消費する場合は、インスタンスを正常な状態に保つために、同時実行を制限することができます。 同様に、スロットルされているダウンストリーム サービスに対して関数が要求を行っている場合も、同時実行数を制限することを検討する必要があります。

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

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

動的な同時実行制御 (プレビュー)

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

注意

現在、動的な同時実行制御は、Service Bus トリガーでのみサポートされており、Microsoft.Azure.WebJobs.Extensions.ServiceBus 拡張機能のバージョン 5.0.0-beta.6 (またはそれ以降) を使用する必要があります。

メリット

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

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

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

動的な同時実行制御は、host.json ファイルでホスト レベルで有効にすることができます。 有効にすると、動的な同時実行制御をサポートする関数アプリで使用されるバインド拡張機能により、必要に応じて同時実行が動的に調整されます。 動的な同時実行制御の設定は、動的な同時実行をサポートするトリガーに対して手動で構成された同時実行制御の設定を上書きします。

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

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

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

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

同時実行マネージャー

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

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

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

拡張機能のサポート

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

Service Bus

現在、Service Bus トリガーでは、3 つの実行モデルをサポートしています。 動的な同時実行制御は、これらの実行モデルに次のような影響を与えます。

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

Service Bus トリガーで動的な同時実行制御を使用するには、Microsoft.Azure.WebJobs.Extensions.ServiceBus 拡張機能のバージョン 5.0.0-beta.6 (またはそれ以降) を使用する必要があります。

次のステップ

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