Azure Functions での接続の管理
[アーティクル] 2023/06/01
12 人の共同作成者
フィードバック
この記事の内容
接続の制限
静的クライアント
クライアント コードの例
SqlClient の接続
次の手順
関数アプリ内の関数はリソースを共有します。 それらの共有リソースの中には、HTTP 接続、データベース接続、Azure Storage などのサービスへの接続があります。 従量課金プランで多くの関数が同時に実行されている場合、利用可能な接続が不足する可能性があります。 この記事では、必要以上に多くの接続を使用しないように関数をコーディングする方法について説明します。
注意
この記事で説明する接続制限は、従量消費プラン で実行されている場合にのみ適用されます。 ただし、ここで説明する手法は、どのようなプランで実行しても役立つ場合があります。
従量課金プランで利用できる接続数が制限される理由の一部は、このプランの関数アプリがサンドボックス環境 で実行されることにあります。 サンドボックスがコードに課す制限の 1 つに、送信接続数の制限があります。現在は、インスタンスあたり 600 アクティブ (合計 1,200) 接続です。 この制限に達すると、関数ランタイムによって Host thresholds exceeded: Connections
というメッセージがログに出力されます。 詳細については、Functions のサービスの制限 に関する記事を参照してください。
この制限はインスタンスごとに適用されます。 より多くの要求を処理するために、スケール コントローラーによって関数アプリ インスタンスが追加 されると、インスタンスごとに接続の制限が適用されます。 つまり、接続のグローバルな制限はないので、すべてのアクティブ インスタンスでアクティブな接続の数が 600 をはるかに超える可能性があります。
トラブルシューティングを行う際には、関数アプリに対して Application Insights を有効にしたことを確認します。 Application Insights では、実行など、関数アプリのメトリックを表示できます。 詳細については、「Application Insights でテレメトリを表示する 」を参照してください。
必要以上に多くの接続を保持しないようにするには、関数の呼び出しごとに新しいインスタンスを作成するのではなく、クライアント インスタンスを再利用します。 関数の記述に使用するどの言語でも、クライアント接続を再利用することをお勧めします。 たとえば、単一の静的クライアントを使用すると、HttpClient 、DocumentClient 、Azure Storage クライアントなどの .NET クライアントで接続を管理できます。
Azure Functions アプリケーションでサービス固有のクライアントを使用する場合のガイドラインを次に示します。
関数呼び出しごとに新しいクライアントを作成しない 。
すべての関数呼び出しで使用できる単一の静的クライアントを作成する 。
さまざまな関数が同じサービスを使用している場合は、共有ヘルパー クラスで単一の静的クライアントを作成することを検討する 。
このセクションでは、関数のコードからクライアントを作成および使用するためのベスト プラクティスを示します。
静的 HttpClient インスタンスを作成する C# 関数コードの例を次に示します。
// Create a single, static HttpClient
private static HttpClient httpClient = new HttpClient();
public static async Task Run(string input)
{
var response = await httpClient.GetAsync("https://example.com");
// Rest of function
}
.NET の HttpClient について、"クライアントを破棄する方がよいですか" という質問がよく寄せられます。一般に、IDisposable
を実装したオブジェクトは、使用の終了後に破棄します。 ただし、関数の終了時に静的クライアントの使用は終了しないため、静的クライアントは破棄しません。 アプリケーションの起動中は、静的クライアントを存続することができます。
優れた接続管理オプションが提供されることから、node-fetch
モジュールなどの非ネイティブ メソッドではなくネイティブの http.agent
クラスを使用する必要があります。 接続パラメーターは、http.agent
クラスのオプションを使用して構成されます。 HTTP エージェントで利用できるオプションの詳細については、new Agent([options]) を参照してください。
http.request()
で使用されるグローバル http.globalAgent
クラスでは、これらのすべての値がそれぞれの既定値に設定されます。 関数の接続制限を構成するための推奨される方法は、グローバルに最大数を設定することです。 次の例は、関数アプリのソケットの最大数を設定します。
http.globalAgent.maxSockets = 200;
次の例では、その要求専用のカスタム HTTP エージェントを使用する新しい HTTP 要求を作成します。
var http = require('http');
var httpAgent = new http.Agent();
httpAgent.maxSockets = 200;
const options = { agent: httpAgent };
http.request(options, onResponseCallback);
CosmosClient は、Azure Cosmos DB のインスタンスに接続します。 Azure Cosmos DB のドキュメントでは、アプリケーションの有効期間中はシングルトン Azure Cosmos DB クライアントを使用する ことが推奨されています。 次の例では、関数内でそれを行うパターンの 1 つを示します。
#r "Microsoft.Azure.Cosmos"
using Microsoft.Azure.Cosmos;
private static Lazy<CosmosClient> lazyClient = new Lazy<CosmosClient>(InitializeCosmosClient);
private static CosmosClient cosmosClient => lazyClient.Value;
private static CosmosClient InitializeCosmosClient()
{
// Perform any initialization here
var uri = "https://youraccount.documents.azure.com:443";
var authKey = "authKey";
return new CosmosClient(uri, authKey);
}
public static async Task Run(string input)
{
Container container = cosmosClient.GetContainer("database", "collection");
MyItem item = new MyItem{ id = "myId", partitionKey = "myPartitionKey", data = "example" };
await container.UpsertItemAsync(document);
// Rest of function
}
また、トリガー用に "function.proj" という名前のファイルを作成し、次の内容を追加します。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.23.0" />
</ItemGroup>
</Project>
CosmosClient は、Azure Cosmos DB のインスタンスに接続します。 Azure Cosmos DB のドキュメントでは、アプリケーションの有効期間中はシングルトン Azure Cosmos DB クライアントを使用する ことが推奨されています。 次の例では、関数内でそれを行うパターンの 1 つを示します。
const cosmos = require('@azure/cosmos');
const endpoint = process.env.COSMOS_API_URL;
const key = process.env.COSMOS_API_KEY;
const { CosmosClient } = cosmos;
const client = new CosmosClient({ endpoint, key });
// All function invocations also reference the same database and container.
const container = client.database("MyDatabaseName").container("MyContainerName");
module.exports = async function (context) {
const { resources: itemArray } = await container.items.readAll().fetchAll();
context.log(itemArray);
}
関数コードでは、SQL リレーショナル データベースに接続するために、.NET Framework Data Provider for SQL Server (SqlClient ) を使用できます。 これは、ADO.NET に依存するデータ フレームワーク (Entity Framework など) の基になるプロバイダーでもあります。 HttpClient や DocumentClient の接続とは異なり、ADO.NET は接続プールを既定で実装します。 ただし、それでも接続を使い果たす可能性があるため、データベースへの接続を最適化する必要があります。 詳しくは、「SQL Server の接続プール (ADO.NET) 」をご覧ください。
ヒント
Entity Framework などの一部のデータ フレームワークは、通常、構成ファイルの ConnectionStrings セクションから接続文字列を取得します。 その場合は、関数アプリの設定およびローカル プロジェクトの local.settings.json ファイル の接続文字列 コレクションに、SQL データベースの接続文字列を明示的に追加する必要があります。 関数コードで SqlConnection のインスタンスを作成する場合は、他の接続と共に、接続文字列の値をアプリケーションの設定 に保存する必要があります。
静的クライアントが推奨される理由の詳細については、「不適切なインスタンス化のアンチパターン 」をご覧ください。
Azure Functions のパフォーマンスに関するその他のヒントについては、「Azure Functions のパフォーマンスと信頼性を最適化する 」を参照してください。