HttpClientインスタンスは1つにし、MaxConnectionsPerServerを適切に設定する
HttpClientの利用でソケット枯渇しないように、using (var httpClient = new HttpClient())のようにインスタンスを使い捨てにせずにprivate static HttpClient _httpClient = new HttpClient();でインスタンスを使いまわす記事がありますが、これはシングルスレッドでの処理では効果がありますが、マルチスレッドの高負荷環境ではソケット枯渇が発生します。
ソケット枯渇発生についての詳細は、他の方の記事にが参考になりますので、ここでは割愛しますが、MaxConnectionsPerServerのデフォルトがint.MaxValueで接続数が実質無制限のため、
次のように明示的に接続数を設定する事が必要です。
private static HttpClient _httpClient = new HttpClient(new HttpClientHandler
{
MaxConnectionsPerServer = 4
});
Azure Stotage ライブラリ内のHttpClientの接続数
Azure StorageのBLOBやQueueのAPI処理でも先の原因でソケット枯渇が発生します。
(Azure FunctionsのQueueTriggerなどマルチスレッドで処理する環境では高負荷時にSocketException発生します)
Azure Stotage ライブラリのv9.4.1からCloudBlobClientやCloudQueueClientコンストラクタにDelegatingHandlerパラメータが追加されていますので、次のようにハンドラを実装し接続数を指定すると良いようです。
(.Net Core v3.0, Microsoft.Azure.Storage.Blob(v11.1.3), Microsoft.Azure.Storage.Queue(v11.1.3)で確認)
public class HttpClientInjectionHandler : DelegatingHandler
{
private bool IsFirstCall = true;
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (IsFirstCall)
{
var handler = (HttpClientHandler)InnerHandler;
handler.MaxConnectionsPerServer = 5;
IsFirstCall = false;
}
return base.SendAsync(request, cancellationToken);
}
}
private static CloudStorageAccount _storageAccount = CloudStorageAccount.Parse(@"Connection String...");
private static CloudBlobClient _blobClient = new CloudBlobClient(_storageAccount.BlobEndpoint, _storageAccount.Credentials, new HttpClientInjectionHandler());
Azure Storage ライブラリのバージョン メモ
~v9.3.3: WindowsAzure.Storage
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
v9.4.0~v11: Microsoft.Azure.Storage.Blob
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
v12 azure.Storage.Blobs
v11までとクラス名が異なる。v12にはコンストラクタにDelegatingHandlerパラメータが無いまま。
~v11:CloudBlobClient
v12~:BlobServiceClient