Azure Functions のパフォーマンスと信頼性を最適化するOptimize the performance and reliability of Azure Functions

この記事では、サーバーレス関数アプリのパフォーマンスと信頼性を向上させるためのガイダンスを紹介しています。This article provides guidance to improve the performance and reliability of your serverless function apps.

一般的なベスト プラクティスGeneral best practices

Azure Functions を使用して、サーバーレス ソリューションを構築および設計する際のベスト プラクティスを以下に示します。The following are best practices in how you build and architect your serverless solutions using Azure Functions.

実行時間の長い関数を使用しないAvoid long running functions

サイズが大きく実行時間の長い関数では、予期しないタイムアウトの問題が発生する可能性があります。Large, long-running functions can cause unexpected timeout issues. Node.js の依存関係が多いと、関数のサイズが大きくなることがあります。A function can become large due to many Node.js dependencies. また、依存関係をインポートすると、読み込み時間が長くなり、予期しないタイムアウトが発生する可能性もあります。Importing dependencies can also cause increased load times that result in unexpected timeouts. 依存関係は明示的にも暗黙的にも読み込まれます。Dependencies are loaded both explicitly and implicitly. コードによって読み込まれる単一のモジュールによって、独自の追加モジュールが読み込まれることがあります。A single module loaded by your code may load its own additional modules.

可能な限り、大きな関数は、連携して高速な応答を返す、より小さな関数セットにリファクタリングしてください。Whenever possible, refactor large functions into smaller function sets that work together and return responses fast. たとえば、webhook または HTTP トリガー関数では、一定の時間内に確認応答が必要になる場合があります。webhook は通常、即座に応答を必要とします。For example, a webhook or HTTP trigger function might require an acknowledgment response within a certain time limit; it is common for webhooks to require an immediate response. この HTTP トリガー ペイロードは、キュー トリガー関数によって処理されるキューに渡すことができます。You can pass the HTTP trigger payload into a queue to be processed by a queue trigger function. このアプローチを使用すると、実際の作業を遅らせて、即座に応答を返すことができます。This approach allows you to defer the actual work and return an immediate response.

関数間の通信Cross function communication

Durable FunctionsAzure Logic Apps は、状態遷移と複数の関数間での通信を管理するように構築されています。Durable Functions and Azure Logic Apps are built to manage state transitions and communication between multiple functions.

複数の関数と統合する際に Durable Functions も Logic Apps も使用しない場合、ベスト プラクティスとして、関数間通信にストレージ キューを使用するのが一般的です。If not using Durable Functions or Logic Apps to integrate with multiple functions, it is generally a best practice to use storage queues for cross function communication. その主な理由は、ストレージ キューの方が安価であり、プロビジョニングがはるかに容易なためです。The main reason is storage queues are cheaper and much easier to provision.

ストレージ キュー内では、個々のメッセージのサイズが 64 KB に制限されます。Individual messages in a storage queue are limited in size to 64 KB. 関数間でこれよりも大きなメッセージを渡す必要がある場合は、Azure Service Bus キューを使用して最大 256 KB のメッセージ サイズをサポートできます。If you need to pass larger messages between functions, an Azure Service Bus queue could be used to support message sizes up to 256 KB.

メッセージの処理の前にフィルター処理を必要とする場合は、Service Bus のトピックが役立ちます。Service Bus topics are useful if you require message filtering before processing.

イベント ハブは、大量の通信をサポートするのに便利です。Event hubs are useful to support high volume communications.

ステートレスな関数を記述するWrite functions to be stateless

可能であれば、関数はステートレスかつべき等である必要があります。Functions should be stateless and idempotent if possible. すべての必要な状態情報をデータに関連付けます。Associate any required state information with your data. たとえば、処理する注文には、state メンバーが関連付けられている可能性があります。For example, an order being processed would likely have an associated state member. 関数は、それ自体がステートレスなまま、その状態に基づいて注文を処理できます。A function could process an order based on that state while the function itself remains stateless.

べき等性を持つ関数は、特にタイマー トリガーと共に使用することをお勧めします。Idempotent functions are especially recommended with timer triggers. たとえば、1 日に 1 回必ず実行する必要のある操作がある場合は、1 日の中の任意の時間にその操作を実行して同じ結果が得られるように記述します。For example, if you have something that absolutely must run once a day, write it so it can run any time during the day with the same results. 特定の日に操作を実行しない場合、この関数は終了することができます。The function can exit when there is no work for a particular day. また、前回の実行が完了しなかった場合は、次の実行では中断した場所から操作を実行する必要があります。Also if a previous run failed to complete, the next run should pick up where it left off.

防御的な関数を記述するWrite defensive functions

関数は時を選ばす例外に遭遇する可能性があることを想定する必要があります。Assume your function could encounter an exception at any time. 関数を設計する場合は、前回失敗した処理を、次回そのポイントから続行する機能を組み込みます。Design your functions with the ability to continue from a previous fail point during the next execution. 次のアクションを必要とするシナリオを考えてみましょう。Consider a scenario that requires the following actions:

  1. データベース内の 10,000 行を照会する。Query for 10,000 rows in a db.
  2. これらの行のそれぞれに対してキュー メッセージを作成して、最後まで処理を実行する。Create a queue message for each of those rows to process further down the line.

システムの複雑さによっては、ダウンストリーム サービスが正しく動作しない、ネットワーキングが停止する、クォータ制限に達するなどの問題が発生する可能性があります。いずれも、時を選ばず関数に影響する可能性があります。Depending on how complex your system is, you may have: involved downstream services behaving badly, networking outages, or quota limits reached, etc. All of these can affect your function at any time. 関数を設計する際は、このような状況を想定する必要があります。You need to design your functions to be prepared for it.

これらのアイテムのうちの 5,000 個を処理のためにキューに入れた後で障害が発生する状況を想定した場合、どのように対応すればよいでしょうか。How does your code react if a failure occurs after inserting 5,000 of those items into a queue for processing? 完了したセット内のアイテムを追跡するようにしましょう。Track items in a set that you’ve completed. そうでないと、次回同じアイテムを再び挿入することになります。Otherwise, you might insert them again next time. その場合、ワークフローに大きな影響が及ぶ可能性があります。This can have a serious impact on your work flow.

キュー アイテムが既に処理されている場合は、関数による操作をなしにします。If a queue item was already processed, allow your function to be a no-op.

Azure Functions プラットフォームで使用するコンポーネントに対して既に提供されている防御策を活用してください。Take advantage of defensive measures already provided for components you use in the Azure Functions platform. 一例として、Azure Storage キューのトリガーとバインドに関するドキュメントの「有害キュー メッセージの処理」を参照してください。For example, see Handling poison queue messages in the documentation for Azure Storage Queue triggers and bindings.

スケーラビリティのベスト プラクティスScalability best practices

関数アプリのインスタンスのスケーリングに影響を及ぼす多数の要素があります。There are a number of factors which impact how instances of your function app scale. 詳細については、関数のスケーリングに関するドキュメントをご覧ください。The details are provided in the documentation for function scaling. 関数アプリの最適なスケーラビリティを確保するためのベスト プラクティスを以下に示します。The following are some best practices to ensure optimal scalability of a function app.

同じ関数アプリにテスト コードと運用環境のコードを混在させないDon't mix test and production code in the same function app

Function App 内の関数はリソースを共有します。Functions within a function app share resources. たとえば、メモリは共有されます。For example, memory is shared. 運用環境で Function App を使用している場合は、テストに関連する関数およびリソースを追加しないでください。If you're using a function app in production, don't add test-related functions and resources to it. これが原因で、運用環境のコードの実行中に予期しないオーバーヘッドが発生する可能性があります。It can cause unexpected overhead during production code execution.

運用環境の Function App で読み込むものに注意してください。Be careful what you load in your production function apps. メモリは、アプリ内の各関数間で平均化されます。Memory is averaged across each function in the app.

複数の .NET 関数で参照される共有アセンブリがある場合は、それを共通の共有フォルダーに配置します。If you have a shared assembly referenced in multiple .Net functions, put it in a common shared folder. C# スクリプト (.csx) を使用している場合は、次の例のようなステートメントを使用してアセンブリを参照します。Reference the assembly with a statement similar to the following example if using C# Scripts (.csx):

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

そうしないと、関数間で動作が異なる同じバイナリの複数のテスト バージョンを誤ってデプロイする可能性があります。Otherwise, it is easy to accidentally deploy multiple test versions of the same binary that behave differently between functions.

運用環境のコードでは、詳細ログ記録を使用しないでください。Don't use verbose logging in production code. パフォーマンスに悪影響が及びます。It has a negative performance impact.

非同期コードを使用し、呼び出しのブロックは避けるUse async code but avoid blocking calls

非同期プログラミングは、推奨されるベスト プラクティスです。Asynchronous programming is a recommended best practice. ただし、Task インスタンスの Result プロパティを参照したり Wait メソッドを呼び出したりすることは、常に避けるようにします。However, always avoid referencing the Result property or calling Wait method on a Task instance. この手法により、スレッドが枯渇する可能性があります。This approach can lead to thread exhaustion.

ヒント

HTTP または webhook のバインディングを使用する予定がある場合は、不適切な HttpClient のインスタンス化によって生じるおそれのあるポートの枯渇を防止してください。If you plan to use the HTTP or WebHook bindings, plan to avoid port exhaustion that can be caused by improper instantiation of HttpClient. 詳細については、「Improper Instantiation antipattern (不適切なインスタンス化の防止策)」の記事を参照してください。For more information, review the article Improper Instantiation antipattern.

可能な限りメッセージをバッチで受信するReceive messages in batch whenever possible

イベント ハブなどの一部のトリガーでは、1 つの呼び出しでメッセージのバッチを受信できます。Some triggers like Event Hub enable receiving a batch of messages on a single invocation. メッセージをバッチ処理すると、パフォーマンスが大幅に向上します。Batching messages has much better performance. host.json のリファレンス ドキュメントで詳述するように、functions.json ファイルで最大バッチ サイズを構成できます。You can configure the max batch size in the functions.json file as detailed in the host.json reference documentation

C# 関数の場合、型を厳密に型指定された配列に変更できます。For C# functions you can change the type to a strongly-typed array. たとえば、メソッド シグネチャに、EventData sensorEvent ではなく EventData[] sensorEvent を指定できます。For example, instead of EventData sensorEvent the method signature could be EventData[] sensorEvent. 他の言語の場合、バッチ処理を有効にするには、こちらに示すように、function.json の cardinality プロパティを明示的に many に設定する必要があります。For other languages you'll need to explicitly set the cardinality property in your function.json to many in order to enable batching as shown here.

同時実行を適切に処理するようにホストの動作を構成するConfigure host behaviors to better handle concurrency

関数アプリの host.json ファイルでは、ホストのランタイムとトリガーの動作を構成できます。The host.json file in the function app allows for configuration of host runtime and trigger behaviors. バッチ処理の動作に加え、多数のトリガーの同時実行を管理できます。In addition to batching behaviors, you can manage concurrency for a number of triggers. 多くの場合、これらのオプションの値を調整することで、呼び出された関数の要求に合わせて各インスタンスを適切にスケールできます。Often adjusting the values in these options can help each instance scale appropriately for the demands of the invoked functions.

hosts ファイルの設定は、アプリ内のすべての関数 (関数の "1 つのインスタンス") に適用されます。Settings in the hosts file apply across all functions within the app, within a single instance of the function. たとえば、2 つの HTTP 関数が含まれ、同時要求数が 25 に設定された関数アプリがある場合、一方の HTTP トリガーに対する要求は共有された 25 の同時要求にカウントされます。For example, if you had a function app with 2 HTTP functions and concurrent requests set to 25, a request to either HTTP trigger would count towards the shared 25 concurrent requests. その関数アプリが 10 インスタンスにスケールされた場合、2 つの関数は 250 個の同時要求に効果的に対応できます (10 インスタンス * インスタンスあたり 25 個の同時要求)。If that function app scaled to 10 instances, the 2 functions would effectively allow 250 concurrent requests (10 instances * 25 concurrent requests per instance).

HTTP 同時実行ホストのオプションHTTP concurrency host options

{
    "http": {
        "routePrefix": "api",
        "maxOutstandingRequests": 20,
        "maxConcurrentRequests": 10,
        "dynamicThrottlesEnabled": false
    }
}
プロパティProperty 既定値Default 説明Description
routePrefixroutePrefix apiapi すべてのルートに適用されるルート プレフィックス。The route prefix that applies to all routes. 既定のプレフィックスを削除するには、空の文字列を使用します。Use an empty string to remove the default prefix.
maxOutstandingRequestsmaxOutstandingRequests -1-1 特定の時点で保持される未処理の要求の最大数。The maximum number of outstanding requests that are held at any given time. この制限には、キューに格納され、まだ実行が開始されていない要求と、処理中の実行が含まれます。This limit includes requests that are queued but have not started executing, as well as any in progress executions. この制限を超える受信要求は、429 "Too Busy" 応答で拒否されます。Any incoming requests over this limit are rejected with a 429 "Too Busy" response. これにより、呼び出し元は時間ベースの再試行戦略を採用でき、要求の最大待機時間の制御にも役立ちます。That allows callers to employ time-based retry strategies, and also helps you to control maximum request latencies. この設定は、スクリプト ホストの実行パス内で発生するキューのみを制御します。This only controls queuing that occurs within the script host execution path. ASP.NET 要求キューなどの他のキューは有効なままで、この設定の影響を受けません。Other queues such as the ASP.NET request queue will still be in effect and unaffected by this setting. 既定値は unbounded です。The default is unbounded.
maxConcurrentRequestsmaxConcurrentRequests -1-1 並列で実行される HTTP 関数の最大数。The maximum number of http functions that will be executed in parallel. これにより同時実行を制御でき、リソース使用率の管理に役立ちます。This allows you to control concurrency, which can help manage resource utilization. たとえば、多くのシステム リソース (メモリ、CPU、ソケット) を消費する HTTP 関数があった場合、同時実行率が高すぎると問題が発生します。For example, you might have an http function that uses a lot of system resources (memory/cpu/sockets) such that it causes issues when concurrency is too high. または、サードパーティのサービスに対して要求を送信する関数があり、その呼び出し速度を制限する必要がある場合です。Or you might have a function that makes outbound requests to a third party service, and those calls need to be rate limited. このような場合は、調整を適用することができます。In these cases, applying a throttle here can help. 既定値は unbounded です。The default is unbounded.
dynamicThrottlesEnableddynamicThrottlesEnabled falsefalse この設定を有効にすると、要求処理パイプラインが、システム パフォーマンス カウンター (接続、スレッド、プロセス、メモリ、CPU など) を定期的にチェックし、カウンターのいずれかが組み込まれた上限閾値 (80%) を超えた場合は、カウンターが正常なレベルに戻るまで要求は 429 "Too Busy" 応答で拒否されます。When enabled, this setting causes the request processing pipeline to periodically check system performance counters like connections/threads/processes/memory/cpu/etc. and if any of those counters are over a built-in high threshold (80%), requests will be rejected with a 429 "Too Busy" response until the counter(s) return to normal levels.

他のホスト構成オプションについては、ホスト構成に関するドキュメントをご覧ください。Other host configuration options can be found in the host configuration document.

次のステップNext steps

詳細については、次のリソースを参照してください。For more information, see the following resources:

Azure Functions は Azure App Service を使用するため、App Service のガイドラインも認識しておく必要があります。Because Azure Functions uses Azure App Service, you should also be aware of App Service guidelines.