Azure Functions での接続の管理

関数アプリ内の関数はリソースを共有します。 それらの共有リソースの中には、HTTP 接続、データベース接続、Azure Storage などのサービスへの接続があります。 従量課金プランで多くの関数が同時に実行されている場合、利用可能な接続が不足する可能性があります。 この記事では、必要以上に多くの接続を使用しないように関数をコーディングする方法について説明します。

Note

この記事で説明する接続制限は、従量消費プランで実行されている場合にのみ適用されます。 ただし、ここで説明する手法は、どのようなプランで実行しても役立つ場合があります。

接続の制限

従量課金プランで利用できる接続数が制限される理由の一部は、このプランの関数アプリがサンドボックス環境で実行されることにあります。 サンドボックスがコードに課す制限の 1 つに、送信接続数の制限があります。現在は、インスタンスあたり 600 アクティブ (合計 1,200) 接続です。 この制限に達すると、関数ランタイムによって Host thresholds exceeded: Connections というメッセージがログに出力されます。 詳細については、Functions のサービスの制限に関する記事を参照してください。

この制限はインスタンスごとに適用されます。 より多くの要求を処理するために、スケール コントローラーによって関数アプリ インスタンスが追加されると、インスタンスごとに接続の制限が適用されます。 つまり、接続のグローバルな制限はないので、すべてのアクティブ インスタンスでアクティブな接続の数が 600 をはるかに超える可能性があります。

トラブルシューティングを行う際には、関数アプリに対して Application Insights を有効にしたことを確認します。 Application Insights では、実行など、関数アプリのメトリックを表示できます。 詳細については、「Application Insights でテレメトリを表示する」を参照してください。

静的クライアント

必要以上に多くの接続を保持しないようにするには、関数の呼び出しごとに新しいインスタンスを作成するのではなく、クライアント インスタンスを再利用します。 関数の記述に使用するどの言語でも、クライアント接続を再利用することをお勧めします。 たとえば、単一の静的クライアントを使用すると、HttpClientDocumentClient、Azure Storage クライアントなどの .NET クライアントで接続を管理できます。

Azure Functions アプリケーションでサービス固有のクライアントを使用する場合のガイドラインを次に示します。

  • 関数呼び出しごとに新しいクライアントを作成しない
  • すべての関数呼び出しで使用できる単一の静的クライアントを作成する
  • さまざまな関数が同じサービスを使用している場合は、共有ヘルパー クラスで単一の静的クライアントを作成することを検討する

クライアント コードの例

このセクションでは、関数のコードからクライアントを作成および使用するためのベスト プラクティスを示します。

HTTP 要求

静的 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 を実装したオブジェクトは、使用の終了後に破棄します。 ただし、関数の終了時に静的クライアントの使用は終了しないため、静的クライアントは破棄しません。 アプリケーションの起動中は、静的クライアントを存続することができます。

Azure Cosmos DB クライアント

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>

SqlClient の接続

関数コードでは、SQL リレーショナル データベースに接続するために、.NET Framework Data Provider for SQL Server (SqlClient) を使用できます。 これは、ADO.NET に依存するデータ フレームワーク (Entity Framework など) の基になるプロバイダーでもあります。 HttpClientDocumentClient の接続とは異なり、ADO.NET は接続プールを既定で実装します。 ただし、それでも接続を使い果たす可能性があるため、データベースへの接続を最適化する必要があります。 詳しくは、「SQL Server の接続プール (ADO.NET)」をご覧ください。

ヒント

Entity Framework などの一部のデータ フレームワークは、通常、構成ファイルの ConnectionStrings セクションから接続文字列を取得します。 その場合は、関数アプリの設定およびローカル プロジェクトの local.settings.json ファイル接続文字列コレクションに、SQL データベースの接続文字列を明示的に追加する必要があります。 関数コードで SqlConnection のインスタンスを作成する場合は、他の接続と共に、接続文字列の値をアプリケーションの設定に保存する必要があります。

次の手順

静的クライアントが推奨される理由の詳細については、「不適切なインスタンス化のアンチパターン」をご覧ください。

Azure Functions のパフォーマンスに関するその他のヒントについては、「Azure Functions のパフォーマンスと信頼性を最適化する」を参照してください。