Azure Functions のパフォーマンスと信頼性を最適化する

この記事では、関数アプリのパフォーマンスと信頼性を向上させるためのガイダンスを紹介しています。

実行時間の長い関数を使用しない

サイズが大きく実行時間の長い関数では、予期しないタイムアウトの問題が発生する可能性があります。 Node.js の依存関係が多いと、関数のサイズが大きくなることがあります。 また、依存関係をインポートすると、読み込み時間が長くなり、予期しないタイムアウトが発生する可能性もあります。 依存関係は明示的にも暗黙的にも読み込まれます。 コードによって読み込まれる単一のモジュールによって、独自の追加モジュールが読み込まれることがあります。

可能な限り、大きな関数は、連携して高速な応答を返す、より小さな関数セットにリファクタリングしてください。 たとえば、webhook または HTTP トリガー関数では、一定の時間内に確認応答が必要になる場合があります。webhook は通常、即座に応答を必要とします。 この HTTP トリガー ペイロードは、キュー トリガー関数によって処理されるキューに渡すことができます。 このアプローチを使用すると、実際の作業を遅らせて、即座に応答を返すことができます。

関数間の通信

複数の関数を統合する場合の一般的なベスト プラクティスは、関数間通信にストレージ キューを使用することです。 その主な理由は、ストレージ キューの方が安価であり、プロビジョニングがはるかに容易なためです。

ストレージ キュー内では、個々のメッセージのサイズが 64 KB に制限されます。 関数間でこれよりも大きなメッセージを渡す必要がある場合は、Azure Service Bus キューを使用して最大 256 KB のメッセージ サイズをサポートできます。

メッセージの処理の前にフィルター処理を必要とする場合は、Service Bus のトピックが役立ちます。

イベント ハブは、大量の通信をサポートするのに便利です。

ステートレスな関数を記述する

可能であれば、関数はステートレスかつべき等である必要があります。 すべての必要な状態情報をデータに関連付けます。 たとえば、処理する注文には、state メンバーが関連付けられている可能性があります。 関数は、それ自体がステートレスなまま、その状態に基づいて注文を処理できます。

べき等性を持つ関数は、特にタイマー トリガーと共に使用することをお勧めします。 たとえば、1 日に 1 回必ず実行する必要のある操作がある場合は、1 日の中の任意の時間にその操作を実行して同じ結果が得られるように記述します。 特定の日に操作を実行しない場合、この関数は終了することができます。 また、前回の実行が完了しなかった場合は、次の実行では中断した場所から操作を実行する必要があります。

防御的な関数を記述する

関数は時を選ばす例外に遭遇する可能性があることを想定する必要があります。 関数を設計する場合は、前回失敗した処理を、次回そのポイントから続行する機能を組み込みます。 次のアクションを必要とするシナリオを考えてみましょう。

  1. データベース内の 10,000 行を照会する。
  2. これらの行のそれぞれに対してキュー メッセージを作成して、最後まで処理を実行する。

システムの複雑さによっては、ダウンストリーム サービスが正しく動作しない、ネットワーキングが停止する、クォータ制限に達するなどの問題が発生する可能性があります。いずれも、時を選ばず関数に影響する可能性があります。 関数を設計する際は、このような状況を想定する必要があります。

これらのアイテムのうちの 5,000 個を処理のためにキューに入れた後で障害が発生する状況を想定した場合、どのように対応すればよいでしょうか。 完了したセット内のアイテムを追跡するようにしましょう。 そうでないと、次回同じアイテムを再び挿入することになります。 その場合、ワークフローに大きな影響が及ぶ可能性があります。

キュー アイテムが既に処理されている場合は、関数による操作をなしにします。

Azure Functions プラットフォームで使用するコンポーネントに対して既に提供されている防御策を活用してください。 一例として、「Azure Storage キュー トリガー」の「有害キュー メッセージの処理」を参照してください。

同じ関数アプリにテスト コードと運用環境のコードを混在させない

Function App 内の関数はリソースを共有します。 たとえば、メモリは共有されます。 運用環境で Function App を使用している場合は、テストに関連する関数およびリソースを追加しないでください。 これが原因で、運用環境のコードの実行中に予期しないオーバーヘッドが発生する可能性があります。

運用環境の Function App で読み込むものに注意してください。 メモリは、アプリ内の各関数間で平均化されます。

複数の .NET 関数で参照される共有アセンブリがある場合は、それを共通の共有フォルダーに配置します。 次の例のようなステートメントを使用して、アセンブリを参照します。

#r "..\Shared\MyAssembly.dll". 

そうしないと、関数間で動作が異なる同じバイナリの複数のテスト バージョンを誤ってデプロイする可能性があります。

運用環境のコードでは、詳細ログ記録を使用しないでください。 パフォーマンスに悪影響が及びます。

非同期コードを使用する。ただし Task.Result は避ける

非同期プログラミングは、推奨されるベスト プラクティスです。 ただし、Task.Result プロパティを参照することは必ず避けてください。 この手法により、スレッドが枯渇する可能性があります。

ヒント

HTTP または webhook のバインディングを使用する予定がある場合は、不適切な HttpClient のインスタンス化によって生じるおそれのあるポートの枯渇を防止してください。 詳細については、「Improper Instantiation antipattern (不適切なインスタンス化の防止策)」の記事を参照してください。

次のステップ

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

Azure Functions は Azure App Service を使用するため、App Service のガイドラインも認識しておく必要があります。